You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ap...@apache.org on 2013/04/19 08:14:29 UTC
[3/4] Storage motion for Xenserver changes: 1. Implemented Api
findStoragePoolsForMigration. Added a new response objects to list storage
pools available for migration. 2. Updated migrateVolume api for allowing
migrating volumes of running vms. These cha
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
index b619ee9..a84f308 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
@@ -18,11 +18,18 @@
*/
package org.apache.cloudstack.storage.test;
+import java.util.Map;
+
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.apache.cloudstack.storage.motion.DataMotionStrategy;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
public class MockStorageMotionStrategy implements DataMotionStrategy {
@Override
@@ -32,6 +39,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
}
@Override
+ public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+ return true;
+ }
+
+ @Override
public Void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
CopyCommandResult result = new CopyCommandResult("something", null);
@@ -39,4 +51,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
return null;
}
+ @Override
+ public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+ AsyncCompletionCallback<CopyCommandResult> callback) {
+ CopyCommandResult result = new CopyCommandResult("something", null);
+ callback.complete(result);
+ return null;
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 3602bb1..ad9238a 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -20,12 +20,14 @@ package org.apache.cloudstack.storage.motion;
import java.util.Date;
import java.util.List;
+import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -36,6 +38,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
+import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.BackupSnapshotAnswer;
import com.cloud.agent.api.BackupSnapshotCommand;
@@ -47,15 +50,21 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
import com.cloud.agent.api.UpgradeSnapshotCommand;
import com.cloud.agent.api.storage.CopyVolumeAnswer;
import com.cloud.agent.api.storage.CopyVolumeCommand;
+import com.cloud.agent.api.storage.MigrateVolumeAnswer;
+import com.cloud.agent.api.storage.MigrateVolumeCommand;
import com.cloud.agent.api.storage.CreateAnswer;
import com.cloud.agent.api.storage.CreateCommand;
import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
import com.cloud.agent.api.to.S3TO;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.agent.api.to.SwiftTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.configuration.Config;
import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.OperationTimedoutException;
import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.DiskOfferingVO;
@@ -86,6 +95,8 @@ import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.DiskProfile;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
@Component
public class AncientDataMotionStrategy implements DataMotionStrategy {
@@ -102,8 +113,12 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
@Inject
StorageManager storageMgr;
@Inject
+ AgentManager agentMgr;
+ @Inject
VolumeDao volDao;
@Inject
+ VMInstanceDao instanceDao;
+ @Inject
VMTemplateDao templateDao;
@Inject
SnapshotManager snapshotMgr;
@@ -130,6 +145,11 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
return true;
}
+ @Override
+ public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+ return false;
+ }
+
@DB
protected Answer copyVolumeFromImage(DataObject srcData, DataObject destData) {
String value = configDao.getValue(Config.RecreateSystemVmEnabled.key());
@@ -393,6 +413,53 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
return cvAnswer;
}
+ protected Answer migrateVolumeToPool(DataObject srcData, DataStore destStore) {
+ VolumeInfo volume = (VolumeInfo)srcData;
+ Long instanceId = volume.getInstanceId();
+ StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destStore.getId(), DataStoreRole.Primary);
+ MigrateVolumeAnswer answer = null;
+ VMInstanceVO vmInstance = null;
+ if (instanceId != null) {
+ vmInstance = instanceDao.findById(instanceId);
+ }
+
+ Long hostId = null;
+ if (vmInstance != null) {
+ hostId = vmInstance.getHostId();
+ }
+
+ try {
+ if (hostId != null) {
+ MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool);
+ answer = (MigrateVolumeAnswer) this.agentMgr.send(hostId, command);
+ }
+ } catch (OperationTimedoutException e) {
+ s_logger.error("Operation timed out on storage motion for volume " + volume, e);
+ throw new CloudRuntimeException("Failed to live migrate volume " + volume + " to storage pool " +
+ destPool, e);
+ } catch (AgentUnavailableException e) {
+ s_logger.error("Agent unavailable exception while doing storage motion for volume " + volume, e);
+ throw new CloudRuntimeException("Failed to live migrate volume " + volume + " to storage pool " +
+ destPool, e);
+ }
+
+ if (answer == null || !answer.getResult()) {
+ throw new CloudRuntimeException("Failed to migrate volume " + volume + " to storage pool " + destPool);
+ } else {
+ // Update the volume details after migration.
+ VolumeVO volumeVo = this.volDao.findById(volume.getId());
+ Long oldPoolId = volume.getPoolId();
+ volumeVo.setPath(answer.getVolumePath());
+ volumeVo.setFolder(destPool.getPath());
+ volumeVo.setPodId(destPool.getPodId());
+ volumeVo.setPoolId(destPool.getId());
+ volumeVo.setLastPoolId(oldPoolId);
+ this.volDao.update(volume.getId(), volumeVo);
+ }
+
+ return answer;
+ }
+
@Override
public Void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback) {
@@ -419,7 +486,12 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
answer = cloneVolume(srcData, destData);
} else if (destData.getType() == DataObjectType.VOLUME
&& srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
- answer = copyVolumeBetweenPools(srcData, destData);
+ if (srcData.getId() == destData.getId()) {
+ // The volume has to be migrated across storage pools.
+ answer = migrateVolumeToPool(srcData, destData.getDataStore());
+ } else {
+ answer = copyVolumeBetweenPools(srcData, destData);
+ }
} else if (srcData.getType() == DataObjectType.SNAPSHOT &&
destData.getType() == DataObjectType.SNAPSHOT) {
answer = copySnapshot(srcData, destData);
@@ -435,6 +507,16 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
return null;
}
+ @Override
+ public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+ AsyncCompletionCallback<CopyCommandResult> callback) {
+ CopyCommandResult result = new CopyCommandResult(null, null);
+ result.setResult("Unsupported operation requested for copying data.");
+ callback.complete(result);
+
+ return null;
+ }
+
@DB
protected Answer createTemplateFromSnashot(DataObject srcData,
DataObject destData) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
index db36f64..5ecbcb3 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
@@ -18,11 +18,20 @@
*/
package org.apache.cloudstack.storage.motion;
+import java.util.Map;
+
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
public interface DataMotionService {
public void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback);
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+ Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
index 343140f..b74e10c 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
@@ -19,14 +19,19 @@
package org.apache.cloudstack.storage.motion;
import java.util.List;
+import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
import org.springframework.stereotype.Component;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
@@ -58,4 +63,15 @@ public class DataMotionServiceImpl implements DataMotionService {
throw new CloudRuntimeException("can't find strategy to move data");
}
+ @Override
+ public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+ Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+ for (DataMotionStrategy strategy : strategies) {
+ if (strategy.canHandle(volumeMap, srcHost, destHost)) {
+ strategy.copyAsync(volumeMap, vmTo, srcHost, destHost, callback);
+ return;
+ }
+ }
+ throw new CloudRuntimeException("can't find strategy to move data");
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
index ba40c6d..e3859b4 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
@@ -18,13 +18,23 @@
*/
package org.apache.cloudstack.storage.motion;
+import java.util.Map;
+
import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
public interface DataMotionStrategy {
public boolean canHandle(DataObject srcData, DataObject destData);
+ public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
public Void copyAsync(DataObject srcData, DataObject destData,
AsyncCompletionCallback<CopyCommandResult> callback);
+ public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+ AsyncCompletionCallback<CopyCommandResult> callback);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index ceadb25..ea31be3 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -176,6 +176,8 @@ public class VolumeObject implements VolumeInfo {
volEvent = Volume.Event.CreateRequested;
} else if (event == ObjectInDataStoreStateMachine.Event.CopyingRequested) {
volEvent = Volume.Event.CopyRequested;
+ } else if (event == ObjectInDataStoreStateMachine.Event.MigrationRequested) {
+ volEvent = Volume.Event.MigrationRequested;
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 32e7d27..e3526de 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -18,6 +18,10 @@
*/
package org.apache.cloudstack.storage.volume;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
import javax.inject.Inject;
import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
@@ -27,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@@ -40,11 +45,14 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager;
import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.motion.DataMotionService;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
+import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.host.Host;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.Type;
@@ -561,7 +569,163 @@ public class VolumeServiceImpl implements VolumeService {
return null;
}
-
+
+ private class MigrateVolumeContext<T> extends AsyncRpcConext<T> {
+ final VolumeInfo srcVolume;
+ final VolumeInfo destVolume;
+ final DataStore destStore;
+ final AsyncCallFuture<VolumeApiResult> future;
+ /**
+ * @param callback
+ */
+ public MigrateVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future,
+ VolumeInfo srcVolume, VolumeInfo destVolume, DataStore destStore) {
+ super(callback);
+ this.srcVolume = srcVolume;
+ this.destVolume = destVolume;
+ this.destStore = destStore;
+ this.future = future;
+ }
+ }
+
+ @Override
+ public AsyncCallFuture<VolumeApiResult> migrateVolume(VolumeInfo srcVolume, DataStore destStore) {
+ AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+ VolumeApiResult res = new VolumeApiResult(srcVolume);
+ try {
+ if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) {
+ s_logger.debug("Snapshots are being created on this volume. This volume cannot be migrated now.");
+ res.setResult("Snapshots are being created on this volume. This volume cannot be migrated now.");
+ future.complete(res);
+ return future;
+ }
+
+ VolumeInfo destVolume = this.volFactory.getVolume(srcVolume.getId(), destStore);
+ srcVolume.processEvent(Event.MigrationRequested);
+ MigrateVolumeContext<VolumeApiResult> context = new MigrateVolumeContext<VolumeApiResult>(null, future,
+ srcVolume, destVolume, destStore);
+ AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+ caller.setCallback(caller.getTarget().migrateVolumeCallBack(null, null)).setContext(context);
+ this.motionSrv.copyAsync(srcVolume, destVolume, caller);
+ } catch (Exception e) {
+ s_logger.debug("Failed to copy volume", e);
+ res.setResult(e.toString());
+ future.complete(res);
+ }
+ return future;
+ }
+
+ protected Void migrateVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+ MigrateVolumeContext<VolumeApiResult> context) {
+ VolumeInfo srcVolume = context.srcVolume;
+ VolumeInfo destVolume = context.destVolume;
+ CopyCommandResult result = callback.getResult();
+ AsyncCallFuture<VolumeApiResult> future = context.future;
+ VolumeApiResult res = new VolumeApiResult(srcVolume);
+ try {
+ if (result.isFailed()) {
+ res.setResult(result.getResult());
+ srcVolume.processEvent(Event.OperationFailed);
+ future.complete(res);
+ } else {
+ srcVolume.processEvent(Event.OperationSuccessed);
+ future.complete(res);
+ }
+ } catch (Exception e) {
+ s_logger.error("Failed to process copy volume callback", e);
+ res.setResult(e.toString());
+ future.complete(res);
+ }
+
+ return null;
+ }
+
+ private class MigrateVmWithVolumesContext<T> extends AsyncRpcConext<T> {
+ final Map<VolumeInfo, DataStore> volumeToPool;
+ final AsyncCallFuture<CommandResult> future;
+ /**
+ * @param callback
+ */
+ public MigrateVmWithVolumesContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<CommandResult> future,
+ Map<VolumeInfo, DataStore> volumeToPool) {
+ super(callback);
+ this.volumeToPool = volumeToPool;
+ this.future = future;
+ }
+ }
+
+ @Override
+ public AsyncCallFuture<CommandResult> migrateVolumes(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+ Host srcHost, Host destHost) {
+ AsyncCallFuture<CommandResult> future = new AsyncCallFuture<CommandResult>();
+ CommandResult res = new CommandResult();
+ try {
+ // Check to make sure there are no snapshot operations on a volume and
+ // put it in the migrating state.
+ List<VolumeInfo> volumesMigrating = new ArrayList<VolumeInfo>();
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeMap.entrySet()) {
+ VolumeInfo volume = entry.getKey();
+ if (!this.snapshotMgr.canOperateOnVolume(volume)) {
+ s_logger.debug("Snapshots are being created on a volume. Volumes cannot be migrated now.");
+ res.setResult("Snapshots are being created on a volume. Volumes cannot be migrated now.");
+ future.complete(res);
+
+ // All the volumes that are already in migrating state need to be put back in ready state.
+ for (VolumeInfo volumeMigrating : volumesMigrating) {
+ volumeMigrating.processEvent(Event.OperationFailed);
+ }
+ return future;
+ } else {
+ volume.processEvent(Event.MigrationRequested);
+ volumesMigrating.add(volume);
+ }
+ }
+
+ MigrateVmWithVolumesContext<CommandResult> context = new MigrateVmWithVolumesContext<CommandResult>(null,
+ future, volumeMap);
+ AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+ caller.setCallback(caller.getTarget().migrateVmWithVolumesCallBack(null, null)).setContext(context);
+ this.motionSrv.copyAsync(volumeMap, vmTo, srcHost, destHost, caller);
+
+ } catch (Exception e) {
+ s_logger.debug("Failed to copy volume", e);
+ res.setResult(e.toString());
+ future.complete(res);
+ }
+
+ return future;
+ }
+
+ protected Void migrateVmWithVolumesCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+ MigrateVmWithVolumesContext<CommandResult> context) {
+ Map<VolumeInfo, DataStore> volumeToPool = context.volumeToPool;
+ CopyCommandResult result = callback.getResult();
+ AsyncCallFuture<CommandResult> future = context.future;
+ CommandResult res = new CommandResult();
+ try {
+ if (result.isFailed()) {
+ res.setResult(result.getResult());
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+ VolumeInfo volume = entry.getKey();
+ volume.processEvent(Event.OperationFailed);
+ }
+ future.complete(res);
+ } else {
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+ VolumeInfo volume = entry.getKey();
+ volume.processEvent(Event.OperationSuccessed);
+ }
+ future.complete(res);
+ }
+ } catch (Exception e) {
+ s_logger.error("Failed to process copy volume callback", e);
+ res.setResult(e.toString());
+ future.complete(res);
+ }
+
+ return null;
+ }
+
@Override
public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
----------------------------------------------------------------------
diff --git a/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java b/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
index a672efd..8243f3a 100755
--- a/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
+++ b/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
@@ -55,6 +55,62 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
@Override
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
+ ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+ long dcId = plan.getDataCenterId();
+ Long podId = plan.getPodId();
+ Long clusterId = plan.getClusterId();
+ ServiceOffering offering = vmProfile.getServiceOffering();
+ List<Host> suitableHosts = new ArrayList<Host>();
+
+ if (type == Host.Type.Storage) {
+ return suitableHosts;
+ }
+
+ String hostTag = offering.getHostTag();
+ if(hostTag != null){
+ s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId +
+ " having host tag:" + hostTag);
+ }else{
+ s_logger.debug("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId);
+ }
+
+ // list all computing hosts, regardless of whether they support routing...it's random after all
+ if(hostTag != null){
+ hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
+ }else{
+ hosts.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId));
+ }
+
+ s_logger.debug("Random Allocator found " + hosts.size() + " hosts");
+ if (hosts.size() == 0) {
+ return suitableHosts;
+ }
+
+ Collections.shuffle(hosts);
+ for (Host host : hosts) {
+ if(suitableHosts.size() == returnUpTo){
+ break;
+ }
+
+ if (!avoid.shouldAvoid(host)) {
+ suitableHosts.add(host);
+ } else {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() +" is in avoid set, " +
+ "skipping this and trying other available hosts");
+ }
+ }
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Random Host Allocator returning "+suitableHosts.size() +" suitable hosts");
+ }
+
+ return suitableHosts;
+ }
+
+ @Override
+ public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
long dcId = plan.getDataCenterId();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 4ef583a..46ae35a 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -3358,7 +3358,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
vm.setMemoryLimits(conn, maxMemsize, maxMemsize, minMemsize, maxMemsize);
}
- private void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException {
+ protected void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException {
long beginTime = System.currentTimeMillis();
while (task.getStatus(c) == Types.TaskStatusType.PENDING) {
try {
@@ -3374,7 +3374,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
- private void checkForSuccess(Connection c, Task task) throws XenAPIException, XmlRpcException {
+ protected void checkForSuccess(Connection c, Task task) throws XenAPIException, XmlRpcException {
if (task.getStatus(c) == Types.TaskStatusType.SUCCESS) {
return;
} else {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
index d64e173..96a90a6 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
@@ -132,6 +132,7 @@ public class XenServer56FP1Resource extends XenServer56Resource {
record.affinity = host;
record.otherConfig.remove("disks");
record.otherConfig.remove("default_template");
+ record.otherConfig.remove("mac_seed");
record.isATemplate = false;
record.nameLabel = vmSpec.getName();
record.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
index 8d267b1..bb31136 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
@@ -20,6 +20,9 @@ package com.cloud.hypervisor.xen.resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
import javax.ejb.Local;
@@ -28,7 +31,34 @@ import org.apache.log4j.Logger;
import com.cloud.resource.ServerResource;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.Script;
-
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.storage.MigrateVolumeAnswer;
+import com.cloud.agent.api.storage.MigrateVolumeCommand;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageReceiveAnswer;
+import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.NicTO;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.Network;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Task;
+import com.xensource.xenapi.Types;
+import com.xensource.xenapi.VBD;
+import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VIF;
+import com.xensource.xenapi.VM;
@Local(value=ServerResource.class)
public class XenServer610Resource extends XenServer56FP1Resource {
@@ -55,4 +85,331 @@ public class XenServer610Resource extends XenServer56FP1Resource {
files.add(file);
return files;
}
+
+ @Override
+ public Answer executeRequest(Command cmd) {
+ if (cmd instanceof MigrateWithStorageCommand) {
+ return execute((MigrateWithStorageCommand) cmd);
+ } else if (cmd instanceof MigrateWithStorageReceiveCommand) {
+ return execute((MigrateWithStorageReceiveCommand) cmd);
+ } else if (cmd instanceof MigrateWithStorageSendCommand) {
+ return execute((MigrateWithStorageSendCommand) cmd);
+ } else if (cmd instanceof MigrateWithStorageCompleteCommand) {
+ return execute((MigrateWithStorageCompleteCommand) cmd);
+ } else if (cmd instanceof MigrateVolumeCommand) {
+ return execute((MigrateVolumeCommand) cmd);
+ } else {
+ return super.executeRequest(cmd);
+ }
+ }
+
+ private List<VolumeTO> getUpdatedVolumePathsOfMigratedVm(Connection connection, VM migratedVm,
+ VolumeTO[] volumes) throws CloudRuntimeException {
+ List<VolumeTO> volumeToList = new ArrayList<VolumeTO>();
+
+ try {
+ // Volume paths would have changed. Return that information.
+ Set<VBD> vbds = migratedVm.getVBDs(connection);
+ Map<String, VDI> deviceIdToVdiMap = new HashMap<String, VDI>();
+ // get vdi:vbdr to a map
+ for (VBD vbd : vbds) {
+ VBD.Record vbdr = vbd.getRecord(connection);
+ if (vbdr.type == Types.VbdType.DISK) {
+ VDI vdi = vbdr.VDI;
+ deviceIdToVdiMap.put(vbdr.userdevice, vdi);
+ }
+ }
+
+ for (VolumeTO volumeTo : volumes) {
+ Long deviceId = volumeTo.getDeviceId();
+ VDI vdi = deviceIdToVdiMap.get(deviceId.toString());
+ volumeTo.setPath(vdi.getUuid(connection));
+ volumeToList.add(volumeTo);
+ }
+ } catch (Exception e) {
+ s_logger.error("Unable to get the updated VDI paths of the migrated vm " + e.toString(), e);
+ throw new CloudRuntimeException("Unable to get the updated VDI paths of the migrated vm " + e.toString(), e);
+ }
+
+ return volumeToList;
+ }
+
+ protected MigrateWithStorageAnswer execute(MigrateWithStorageCommand cmd) {
+ Connection connection = getConnection();
+ VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+ Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
+ final String vmName = vmSpec.getName();
+ State state = s_vms.getState(_cluster, vmName);
+ Task task = null;
+
+ synchronized (_cluster.intern()) {
+ s_vms.put(_cluster, _name, vmName, State.Stopping);
+ }
+
+ try {
+ prepareISO(connection, vmSpec.getName());
+ Map<String, String> other = new HashMap<String, String>();
+ other.put("live", "true");
+ Network networkForSm = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
+ Host host = Host.getByUuid(connection, _host.uuid);
+ Map<String,String> token = host.migrateReceive(connection, networkForSm, other);
+
+ // Get the vm to migrate.
+ Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+ VM vmToMigrate = vms.iterator().next();
+
+ // Create the vif map. The vm stays in the same cluster so we have to pass an empty vif map.
+ Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+ Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+ for (Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
+ vdiMap.put(getVDIbyUuid(connection, entry.getKey().getPath()),
+ getStorageRepository(connection, entry.getValue().getUuid()));
+ }
+
+ // Check migration with storage is possible.
+ task = vmToMigrate.assertCanMigrateAsync(connection, token, true, vdiMap, vifMap, other);
+ try {
+ // poll every 1 seconds
+ long timeout = (_migratewait) * 1000L;
+ waitForTask(connection, task, 1000, timeout);
+ checkForSuccess(connection, task);
+ } catch (Types.HandleInvalid e) {
+ s_logger.error("Error while checking if vm " + vmName + " can be migrated to the destination host " +
+ host, e);
+ throw new CloudRuntimeException("Error while checking if vm " + vmName + " can be migrated to the " +
+ "destination host " + host, e);
+ }
+
+ // Migrate now.
+ task = vmToMigrate.migrateSendAsync(connection, token, true, vdiMap, vifMap, other);
+ try {
+ // poll every 1 seconds.
+ long timeout = (_migratewait) * 1000L;
+ waitForTask(connection, task, 1000, timeout);
+ checkForSuccess(connection, task);
+ } catch (Types.HandleInvalid e) {
+ s_logger.error("Error while migrating vm " + vmName + " to the destination host " + host, e);
+ throw new CloudRuntimeException("Error while migrating vm " + vmName + " to the destination host " +
+ host, e);
+ }
+
+ // Volume paths would have changed. Return that information.
+ List<VolumeTO> volumeToList = getUpdatedVolumePathsOfMigratedVm(connection, vmToMigrate, vmSpec.getDisks());
+ vmToMigrate.setAffinity(connection, host);
+ state = State.Stopping;
+
+ return new MigrateWithStorageAnswer(cmd, volumeToList);
+ } catch (Exception e) {
+ s_logger.warn("Catch Exception " + e.getClass().getName() + ". Storage motion failed due to " +
+ e.toString(), e);
+ return new MigrateWithStorageAnswer(cmd, e);
+ } finally {
+ if (task != null) {
+ try {
+ task.destroy(connection);
+ } catch (Exception e) {
+ s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.uuid +" due to " +
+ e.toString());
+ }
+ }
+
+ synchronized (_cluster.intern()) {
+ s_vms.put(_cluster, _name, vmName, state);
+ }
+ }
+ }
+
+ protected MigrateWithStorageReceiveAnswer execute(MigrateWithStorageReceiveCommand cmd) {
+ Connection connection = getConnection();
+ VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+ Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
+
+ try {
+ // Get a map of all the SRs to which the vdis will be migrated.
+ Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
+ for (Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
+ SR sr = getStorageRepository(connection, entry.getValue().getUuid());
+ volumeToSr.put(entry.getKey(), sr);
+ }
+
+ // Get the list of networks to which the vifs will attach.
+ Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
+ for (NicTO nicTo : vmSpec.getNics()) {
+ Network network = getNetwork(connection, nicTo);
+ nicToNetwork.put(nicTo, network);
+ }
+
+ Map<String, String> other = new HashMap<String, String>();
+ other.put("live", "true");
+ Network network = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
+ Host host = Host.getByUuid(connection, _host.uuid);
+ Map<String,String> token = host.migrateReceive(connection, network, other);
+
+ return new MigrateWithStorageReceiveAnswer(cmd, volumeToSr, nicToNetwork, token);
+ } catch (CloudRuntimeException e) {
+ s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageReceiveAnswer(cmd, e);
+ } catch (Exception e) {
+ s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageReceiveAnswer(cmd, e);
+ }
+ }
+
+ protected MigrateWithStorageSendAnswer execute(MigrateWithStorageSendCommand cmd) {
+ Connection connection = getConnection();
+ VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+ Map<VolumeTO, Object> volumeToSr = cmd.getVolumeToSr();
+ Map<NicTO, Object> nicToNetwork = cmd.getNicToNetwork();
+ Map<String, String> token = cmd.getToken();
+ final String vmName = vmSpec.getName();
+ State state = s_vms.getState(_cluster, vmName);
+ Set<VolumeTO> volumeToSet = null;
+ boolean migrated = false;
+ Task task = null;
+
+ synchronized (_cluster.intern()) {
+ s_vms.put(_cluster, _name, vmName, State.Stopping);
+ }
+
+ try {
+ Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+ VM vmToMigrate = vms.iterator().next();
+ Map<String, String> other = new HashMap<String, String>();
+ other.put("live", "true");
+
+ // Create the vdi map which tells what volumes of the vm need to go on which sr on the destination.
+ Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+ for (Map.Entry<VolumeTO, Object> entry : volumeToSr.entrySet()) {
+ if (entry.getValue() instanceof SR) {
+ SR sr = (SR)entry.getValue();
+ VDI vdi = getVDIbyUuid(connection, entry.getKey().getPath());
+ vdiMap.put(vdi, sr);
+ } else {
+ throw new CloudRuntimeException("The object " + entry.getValue() + " passed is not of type SR.");
+ }
+ }
+
+ // Create the vif map.
+ Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+ for (Map.Entry<NicTO, Object> entry : nicToNetwork.entrySet()) {
+ if (entry.getValue() instanceof Network) {
+ Network network = (Network)entry.getValue();
+ VIF vif = getVifByMac(connection, vmToMigrate, entry.getKey().getMac());
+ vifMap.put(vif, network);
+ } else {
+ throw new CloudRuntimeException("The object " + entry.getValue() + " passed is not of type Network.");
+ }
+ }
+
+ // Check migration with storage is possible.
+ task = vmToMigrate.assertCanMigrateAsync(connection, token, true, vdiMap, vifMap, other);
+ try {
+ // poll every 1 seconds.
+ long timeout = (_migratewait) * 1000L;
+ waitForTask(connection, task, 1000, timeout);
+ checkForSuccess(connection, task);
+ } catch (Types.HandleInvalid e) {
+ s_logger.error("Error while checking if vm " + vmName + " can be migrated.", e);
+ throw new CloudRuntimeException("Error while checking if vm " + vmName + " can be migrated.", e);
+ }
+
+ // Migrate now.
+ task = vmToMigrate.migrateSendAsync(connection, token, true, vdiMap, vifMap, other);
+ try {
+ // poll every 1 seconds.
+ long timeout = (_migratewait) * 1000L;
+ waitForTask(connection, task, 1000, timeout);
+ checkForSuccess(connection, task);
+ } catch (Types.HandleInvalid e) {
+ s_logger.error("Error while migrating vm " + vmName, e);
+ throw new CloudRuntimeException("Error while migrating vm " + vmName, e);
+ }
+
+ migrated = true;
+ return new MigrateWithStorageSendAnswer(cmd, volumeToSet);
+ } catch (CloudRuntimeException e) {
+ s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageSendAnswer(cmd, e);
+ } catch (Exception e) {
+ s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageSendAnswer(cmd, e);
+ } finally {
+ if (task != null) {
+ try {
+ task.destroy(connection);
+ } catch (Exception e) {
+ s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.uuid +" due to " +
+ e.toString());
+ }
+ }
+
+ // Keep cluster/vm sync happy.
+ synchronized (_cluster.intern()) {
+ if (migrated) {
+ s_vms.remove(_cluster, _name, vmName);
+ } else {
+ s_vms.put(_cluster, _name, vmName, state);
+ }
+ }
+ }
+ }
+
+ protected MigrateWithStorageCompleteAnswer execute(MigrateWithStorageCompleteCommand cmd) {
+ Connection connection = getConnection();
+ VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+
+ try {
+ Host host = Host.getByUuid(connection, _host.uuid);
+ Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+ VM migratedVm = vms.iterator().next();
+
+ // Check the vm is present on the new host.
+ if (migratedVm == null) {
+ throw new CloudRuntimeException("Couldn't find the migrated vm " + vmSpec.getName() +
+ " on the destination host.");
+ }
+
+ // Volume paths would have changed. Return that information.
+ List<VolumeTO > volumeToSet = getUpdatedVolumePathsOfMigratedVm(connection, migratedVm, vmSpec.getDisks());
+ migratedVm.setAffinity(connection, host);
+
+ synchronized (_cluster.intern()) {
+ s_vms.put(_cluster, _name, vmSpec.getName(), State.Running);
+ }
+
+ return new MigrateWithStorageCompleteAnswer(cmd, volumeToSet);
+ } catch (CloudRuntimeException e) {
+ s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageCompleteAnswer(cmd, e);
+ } catch (Exception e) {
+ s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+ return new MigrateWithStorageCompleteAnswer(cmd, e);
+ }
+ }
+
+ protected MigrateVolumeAnswer execute(MigrateVolumeCommand cmd) {
+ Connection connection = getConnection();
+ String volumeUUID = cmd.getVolumePath();
+ StorageFilerTO poolTO = cmd.getPool();
+
+ try {
+ SR destinationPool = getStorageRepository(connection, poolTO.getUuid());
+ VDI srcVolume = getVDIbyUuid(connection, volumeUUID);
+ Map<String, String> other = new HashMap<String, String>();
+ other.put("live", "true");
+
+ // Live migrate the vdi across pool.
+ Task task = srcVolume.poolMigrateAsync(connection, destinationPool, other);
+ long timeout = (_migratewait) * 1000L;
+ waitForTask(connection, task, 1000, timeout);
+ checkForSuccess(connection, task);
+ VDI dvdi = Types.toVDI(task, connection);
+
+ return new MigrateVolumeAnswer(cmd, true, null, dvdi.getUuid(connection));
+ } catch (Exception e) {
+ String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
+ s_logger.error(msg, e);
+ return new MigrateVolumeAnswer(cmd, false, msg, null);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
new file mode 100644
index 0000000..353f2b5
--- /dev/null
+++ b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.motion;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.MigrateWithStorageReceiveAnswer;
+import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.Host;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Component
+public class XenServerStorageMotionStrategy implements DataMotionStrategy {
+ private static final Logger s_logger = Logger.getLogger(XenServerStorageMotionStrategy.class);
+ @Inject AgentManager agentMgr;
+ @Inject VolumeDao volDao;
+ @Inject VolumeDataFactory volFactory;
+ @Inject PrimaryDataStoreDao storagePoolDao;
+ @Inject VMInstanceDao instanceDao;
+
+ @Override
+ public boolean canHandle(DataObject srcData, DataObject destData) {
+ return false;
+ }
+
+ @Override
+ public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+ return true;
+ }
+
+ @Override
+ public Void copyAsync(DataObject srcData, DataObject destData,
+ AsyncCompletionCallback<CopyCommandResult> callback) {
+ CopyCommandResult result = new CopyCommandResult(null, null);
+ result.setResult("Unsupported operation requested for copying data.");
+ callback.complete(result);
+
+ return null;
+ }
+
+ @Override
+ public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+ AsyncCompletionCallback<CopyCommandResult> callback) {
+ Answer answer = null;
+ String errMsg = null;
+ try {
+ VMInstanceVO instance = instanceDao.findById(vmTo.getId());
+ if (instance != null) {
+ if (srcHost.getClusterId() == destHost.getClusterId()) {
+ answer = migrateVmWithVolumesWithinCluster(instance, vmTo, srcHost, destHost, volumeMap);
+ } else {
+ answer = migrateVmWithVolumesAcrossCluster(instance, vmTo, srcHost, destHost, volumeMap);
+ }
+ } else {
+ throw new CloudRuntimeException("Unsupported operation requested for moving data.");
+ }
+ } catch (Exception e) {
+ s_logger.error("copy failed", e);
+ errMsg = e.toString();
+ }
+
+ CopyCommandResult result = new CopyCommandResult(null, answer);
+ result.setResult(errMsg);
+ callback.complete(result);
+ return null;
+ }
+
+ private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost,
+ Host destHost, Map<VolumeInfo, DataStore> volumeToPool) throws AgentUnavailableException {
+
+ // Initiate migration of a virtual machine with it's volumes.
+ try {
+ Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+ VolumeInfo volume = entry.getKey();
+ VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
+ StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
+ volumeToFilerto.put(volumeTo, filerTo);
+ }
+
+ // Migration across cluster needs to be done in three phases.
+ // 1. Send a migrate receive command to the destination host so that it is ready to receive a vm.
+ // 2. Send a migrate send command to the source host. This actually migrates the vm to the destination.
+ // 3. Complete the process. Update the volume details.
+ MigrateWithStorageReceiveCommand receiveCmd = new MigrateWithStorageReceiveCommand(to, volumeToFilerto);
+ MigrateWithStorageReceiveAnswer receiveAnswer = (MigrateWithStorageReceiveAnswer) agentMgr.send(
+ destHost.getId(), receiveCmd);
+ if (receiveAnswer == null) {
+ s_logger.error("Migration with storage of vm " + vm+ " to host " + destHost + " failed.");
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+ } else if (!receiveAnswer.getResult()) {
+ s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + receiveAnswer.getDetails());
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+ ". " + receiveAnswer.getDetails());
+ }
+
+ MigrateWithStorageSendCommand sendCmd = new MigrateWithStorageSendCommand(to, receiveAnswer.getVolumeToSr(),
+ receiveAnswer.getNicToNetwork(), receiveAnswer.getToken());
+ MigrateWithStorageSendAnswer sendAnswer = (MigrateWithStorageSendAnswer) agentMgr.send(
+ srcHost.getId(), sendCmd);
+ if (sendAnswer == null) {
+ s_logger.error("Migration with storage of vm " + vm+ " to host " + destHost + " failed.");
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+ } else if (!sendAnswer.getResult()) {
+ s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + sendAnswer.getDetails());
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+ ". " + sendAnswer.getDetails());
+ }
+
+ MigrateWithStorageCompleteCommand command = new MigrateWithStorageCompleteCommand(to);
+ MigrateWithStorageCompleteAnswer answer = (MigrateWithStorageCompleteAnswer) agentMgr.send(
+ destHost.getId(), command);
+ if (answer == null) {
+ s_logger.error("Migration with storage of vm " + vm + " failed.");
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+ } else if (!answer.getResult()) {
+ s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + answer.getDetails());
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+ ". " + answer.getDetails());
+ } else {
+ // Update the volume details after migration.
+ updateVolumePathsAfterMigration(volumeToPool, answer.getVolumeTos());
+ }
+
+ return answer;
+ } catch (OperationTimedoutException e) {
+ s_logger.error("Error while migrating vm " + vm + " to host " + destHost, e);
+ throw new AgentUnavailableException("Operation timed out on storage motion for " + vm, destHost.getId());
+ }
+ }
+
+ private Answer migrateVmWithVolumesWithinCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost,
+ Host destHost, Map<VolumeInfo, DataStore> volumeToPool) throws AgentUnavailableException {
+
+ // Initiate migration of a virtual machine with it's volumes.
+ try {
+ Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+ VolumeInfo volume = entry.getKey();
+ VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
+ StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
+ volumeToFilerto.put(volumeTo, filerTo);
+ }
+
+ MigrateWithStorageCommand command = new MigrateWithStorageCommand(to, volumeToFilerto);
+ MigrateWithStorageAnswer answer = (MigrateWithStorageAnswer) agentMgr.send(destHost.getId(), command);
+ if (answer == null) {
+ s_logger.error("Migration with storage of vm " + vm + " failed.");
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+ } else if (!answer.getResult()) {
+ s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + answer.getDetails());
+ throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+ ". " + answer.getDetails());
+ } else {
+ // Update the volume details after migration.
+ updateVolumePathsAfterMigration(volumeToPool, answer.getVolumeTos());
+ }
+
+ return answer;
+ } catch (OperationTimedoutException e) {
+ s_logger.error("Error while migrating vm " + vm + " to host " + destHost, e);
+ throw new AgentUnavailableException("Operation timed out on storage motion for " + vm, destHost.getId());
+ }
+ }
+
+ private void updateVolumePathsAfterMigration(Map<VolumeInfo, DataStore> volumeToPool, List<VolumeTO> volumeTos) {
+ for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+ boolean updated = false;
+ VolumeInfo volume = entry.getKey();
+ StoragePool pool = (StoragePool)entry.getValue();
+ for (VolumeTO volumeTo : volumeTos) {
+ if (volume.getId() == volumeTo.getId()) {
+ VolumeVO volumeVO = volDao.findById(volume.getId());
+ Long oldPoolId = volumeVO.getPoolId();
+ volumeVO.setPath(volumeTo.getPath());
+ volumeVO.setFolder(pool.getPath());
+ volumeVO.setPodId(pool.getPodId());
+ volumeVO.setPoolId(pool.getId());
+ volumeVO.setLastPoolId(oldPoolId);
+ volDao.update(volume.getId(), volumeVO);
+ updated = true;
+ break;
+ }
+ }
+
+ if (!updated) {
+ s_logger.error("Volume path wasn't updated for volume " + volume + " after it was migrated.");
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
index 60027e7..6700f22 100755
--- a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
@@ -21,6 +21,7 @@ import java.util.List;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
+import com.cloud.host.HostVO;
import com.cloud.host.Host.Type;
import com.cloud.offering.ServiceOffering;
import com.cloud.utils.component.Adapter;
@@ -63,8 +64,22 @@ public interface HostAllocator extends Adapter {
**/
public List<Host> allocateTo(VirtualMachineProfile<?extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity);
-
-
- public static int RETURN_UPTO_ALL = -1;
-
+
+ /**
+ * Determines which physical hosts are suitable to
+ * allocate the guest virtual machines on
+ *
+ * @param VirtualMachineProfile vmProfile
+ * @param DeploymentPlan plan
+ * @param GuestType type
+ * @param ExcludeList avoid
+ * @param List<HostVO> hosts
+ * @param int returnUpTo (use -1 to return all possible hosts)
+ * @param boolean considerReservedCapacity (default should be true, set to false if host capacity calculation should not look at reserved capacity)
+ * @return List<Host> List of hosts that are suitable for VM allocation
+ **/
+ public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity);
+
+ public static int RETURN_UPTO_ALL = -1;
+
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
index 0091e43..b54b1c1 100755
--- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
@@ -172,6 +172,53 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
return allocateTo(plan, offering, template, avoid, clusterHosts, returnUpTo, considerReservedCapacity, account);
}
+ @Override
+ public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
+ Type type, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+ long dcId = plan.getDataCenterId();
+ Long podId = plan.getPodId();
+ Long clusterId = plan.getClusterId();
+ ServiceOffering offering = vmProfile.getServiceOffering();
+ VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
+ Account account = vmProfile.getOwner();
+ List<Host> suitableHosts = new ArrayList<Host>();
+
+ if (type == Host.Type.Storage) {
+ // FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of
+ // routing or not.
+ return suitableHosts;
+ }
+
+ String hostTagOnOffering = offering.getHostTag();
+ String hostTagOnTemplate = template.getTemplateTag();
+ boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false;
+ boolean hasTemplateTag = hostTagOnTemplate != null ? true : false;
+
+ String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
+ if (haVmTag != null) {
+ hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, haVmTag));
+ } else {
+ if (hostTagOnOffering == null && hostTagOnTemplate == null){
+ hosts.retainAll(_resourceMgr.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId));
+ } else {
+ if (hasSvcOfferingTag) {
+ hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnOffering));
+ }
+
+ if (hasTemplateTag) {
+ hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate));
+ }
+ }
+ }
+
+ if (!hosts.isEmpty()) {
+ suitableHosts = allocateTo(plan, offering, template, avoid, hosts, returnUpTo, considerReservedCapacity,
+ account);
+ }
+
+ return suitableHosts;
+ }
+
protected List<Host> allocateTo(DeploymentPlan plan, ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity, Account account) {
if (_allocationAlgorithm.equals("random") || _allocationAlgorithm.equals("userconcentratedpod_random")) {
// Shuffle this so that we don't check the hosts in the same order.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
index 90bd956..890c047 100755
--- a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
@@ -29,6 +29,7 @@ import com.cloud.agent.manager.allocator.HostAllocator;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
import com.cloud.host.Host;
+import com.cloud.host.HostVO;
import com.cloud.host.Host.Type;
import com.cloud.host.dao.HostDao;
import com.cloud.offering.ServiceOffering;
@@ -52,6 +53,12 @@ public class TestingAllocator extends AdapterBase implements HostAllocator {
@Override
public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
+ ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+ return allocateTo(vmProfile, plan, type, avoid, returnUpTo, considerReservedCapacity);
+ }
+
+ @Override
+ public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
List<Host> availableHosts = new ArrayList<Host>();
Host host = null;
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index 303f328..c60af27 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -36,6 +36,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainRouterResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse;
@@ -43,6 +44,7 @@ import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
@@ -1518,6 +1520,14 @@ public class ApiDBUtils {
return _hostJoinDao.setHostResponse(vrData, vr);
}
+ public static HostForMigrationResponse newHostForMigrationResponse(HostJoinVO vr, EnumSet<HostDetails> details) {
+ return _hostJoinDao.newHostForMigrationResponse(vr, details);
+ }
+
+ public static HostForMigrationResponse fillHostForMigrationDetails(HostForMigrationResponse vrData, HostJoinVO vr) {
+ return _hostJoinDao.setHostForMigrationResponse(vrData, vr);
+ }
+
public static List<HostJoinVO> newHostView(Host vr){
return _hostJoinDao.newHostView(vr);
}
@@ -1543,6 +1553,15 @@ public class ApiDBUtils {
return _poolJoinDao.setStoragePoolResponse(vrData, vr);
}
+ public static StoragePoolForMigrationResponse newStoragePoolForMigrationResponse(StoragePoolJoinVO vr) {
+ return _poolJoinDao.newStoragePoolForMigrationResponse(vr);
+ }
+
+ public static StoragePoolForMigrationResponse fillStoragePoolForMigrationDetails(StoragePoolForMigrationResponse
+ vrData, StoragePoolJoinVO vr){
+ return _poolJoinDao.setStoragePoolForMigrationResponse(vrData, vr);
+ }
+
public static List<StoragePoolJoinVO> newStoragePoolView(StoragePool vr){
return _poolJoinDao.newStoragePoolView(vr);
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 7629e5e..a7d6165 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -65,6 +65,7 @@ import org.apache.cloudstack.api.response.FirewallRuleResponse;
import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
import org.apache.cloudstack.api.response.IPAddressResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse;
@@ -105,6 +106,7 @@ import org.apache.cloudstack.api.response.SnapshotResponse;
import org.apache.cloudstack.api.response.SnapshotScheduleResponse;
import org.apache.cloudstack.api.response.StaticRouteResponse;
import org.apache.cloudstack.api.response.StorageNetworkIpRangeResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.SwiftResponse;
import org.apache.cloudstack.api.response.SystemVmInstanceResponse;
@@ -511,6 +513,20 @@ public class ApiResponseHelper implements ResponseGenerator {
}
@Override
+ public HostForMigrationResponse createHostForMigrationResponse(Host host) {
+ return createHostForMigrationResponse(host, EnumSet.of(HostDetails.all));
+ }
+
+ @Override
+ public HostForMigrationResponse createHostForMigrationResponse(Host host, EnumSet<HostDetails> details) {
+ List<HostJoinVO> viewHosts = ApiDBUtils.newHostView(host);
+ List<HostForMigrationResponse> listHosts = ViewResponseHelper.createHostForMigrationResponse(details,
+ viewHosts.toArray(new HostJoinVO[viewHosts.size()]));
+ assert listHosts != null && listHosts.size() == 1 : "There should be one host returned";
+ return listHosts.get(0);
+ }
+
+ @Override
public SwiftResponse createSwiftResponse(Swift swift) {
SwiftResponse swiftResponse = new SwiftResponse();
swiftResponse.setId(swift.getUuid());
@@ -908,16 +924,21 @@ public class ApiResponseHelper implements ResponseGenerator {
}
-
-
@Override
public StoragePoolResponse createStoragePoolResponse(StoragePool pool) {
List<StoragePoolJoinVO> viewPools = ApiDBUtils.newStoragePoolView(pool);
List<StoragePoolResponse> listPools = ViewResponseHelper.createStoragePoolResponse(viewPools.toArray(new StoragePoolJoinVO[viewPools.size()]));
assert listPools != null && listPools.size() == 1 : "There should be one storage pool returned";
return listPools.get(0);
+ }
-
+ @Override
+ public StoragePoolForMigrationResponse createStoragePoolForMigrationResponse(StoragePool pool) {
+ List<StoragePoolJoinVO> viewPools = ApiDBUtils.newStoragePoolView(pool);
+ List<StoragePoolForMigrationResponse> listPools = ViewResponseHelper.createStoragePoolForMigrationResponse(
+ viewPools.toArray(new StoragePoolJoinVO[viewPools.size()]));
+ assert listPools != null && listPools.size() == 1 : "There should be one storage pool returned";
+ return listPools.get(0);
}
@Override
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/ViewResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java
index dc2727e..827ae7b 100644
--- a/server/src/com/cloud/api/query/ViewResponseHelper.java
+++ b/server/src/com/cloud/api/query/ViewResponseHelper.java
@@ -30,6 +30,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainRouterResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
import org.apache.cloudstack.api.response.InstanceGroupResponse;
import org.apache.cloudstack.api.response.ProjectAccountResponse;
import org.apache.cloudstack.api.response.ProjectInvitationResponse;
@@ -38,6 +39,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
@@ -230,6 +232,24 @@ public class ViewResponseHelper {
return new ArrayList<HostResponse>(vrDataList.values());
}
+ public static List<HostForMigrationResponse> createHostForMigrationResponse(EnumSet<HostDetails> details,
+ HostJoinVO... hosts) {
+ Hashtable<Long, HostForMigrationResponse> vrDataList = new Hashtable<Long, HostForMigrationResponse>();
+ // Initialise the vrdatalist with the input data
+ for (HostJoinVO vr : hosts) {
+ HostForMigrationResponse vrData = vrDataList.get(vr.getId());
+ if ( vrData == null ) {
+ // first time encountering this vm
+ vrData = ApiDBUtils.newHostForMigrationResponse(vr, details);
+ } else {
+ // update tags
+ vrData = ApiDBUtils.fillHostForMigrationDetails(vrData, vr);
+ }
+ vrDataList.put(vr.getId(), vrData);
+ }
+ return new ArrayList<HostForMigrationResponse>(vrDataList.values());
+ }
+
public static List<VolumeResponse> createVolumeResponse(VolumeJoinVO... volumes) {
Hashtable<Long, VolumeResponse> vrDataList = new Hashtable<Long, VolumeResponse>();
for (VolumeJoinVO vr : volumes) {
@@ -265,6 +285,23 @@ public class ViewResponseHelper {
return new ArrayList<StoragePoolResponse>(vrDataList.values());
}
+ public static List<StoragePoolForMigrationResponse> createStoragePoolForMigrationResponse(StoragePoolJoinVO... pools) {
+ Hashtable<Long, StoragePoolForMigrationResponse> vrDataList = new Hashtable<Long, StoragePoolForMigrationResponse>();
+ // Initialise the vrdatalist with the input data
+ for (StoragePoolJoinVO vr : pools) {
+ StoragePoolForMigrationResponse vrData = vrDataList.get(vr.getId());
+ if ( vrData == null ) {
+ // first time encountering this vm
+ vrData = ApiDBUtils.newStoragePoolForMigrationResponse(vr);
+ } else {
+ // update tags
+ vrData = ApiDBUtils.fillStoragePoolForMigrationDetails(vrData, vr);
+ }
+ vrDataList.put(vr.getId(), vrData);
+ }
+ return new ArrayList<StoragePoolForMigrationResponse>(vrDataList.values());
+ }
+
public static List<AccountResponse> createAccountResponse(AccountJoinVO... accounts) {
List<AccountResponse> respList = new ArrayList<AccountResponse>();
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/dao/HostJoinDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/HostJoinDao.java b/server/src/com/cloud/api/query/dao/HostJoinDao.java
index 1a21299..f526ca3 100644
--- a/server/src/com/cloud/api/query/dao/HostJoinDao.java
+++ b/server/src/com/cloud/api/query/dao/HostJoinDao.java
@@ -21,6 +21,7 @@ import java.util.List;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
import com.cloud.api.query.vo.HostJoinVO;
import com.cloud.host.Host;
import com.cloud.utils.db.GenericDao;
@@ -31,6 +32,10 @@ public interface HostJoinDao extends GenericDao<HostJoinVO, Long> {
HostResponse setHostResponse(HostResponse response, HostJoinVO host);
+ HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, EnumSet<HostDetails> details);
+
+ HostForMigrationResponse setHostForMigrationResponse(HostForMigrationResponse response, HostJoinVO host);
+
List<HostJoinVO> newHostView(Host group);
List<HostJoinVO> searchByIds(Long... ids);