You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ek...@apache.org on 2015/04/05 13:25:13 UTC

[6/8] git commit: updated refs/heads/master to 096d1b9

Refactoring the MigrateWithStorageSendCommand wrapper in order to cope with new design
   - Unit tests added: 47.2% coverage
   - It's a bit difficult to test the Xen API classes due to their static nature


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d5414d26
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d5414d26
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d5414d26

Branch: refs/heads/master
Commit: d5414d26b48ef5da0a5906d39b7e785c13e286a4
Parents: c5a2f92
Author: wilderrodrigues <wr...@schubergphilis.com>
Authored: Fri Apr 3 16:13:09 2015 +0200
Committer: wilderrodrigues <wr...@schubergphilis.com>
Committed: Sun Apr 5 09:23:10 2015 +0200

----------------------------------------------------------------------
 .../resource/XenServer610Resource.java          | 207 +------------------
 .../resource/wrapper/CitrixRequestWrapper.java  |   4 +
 ...igrateWithStorageCompleteCommandWrapper.java |  81 ++++++++
 ...610MigrateWithStorageSendCommandWrapper.java | 143 +++++++++++++
 .../wrapper/XenServer610WrapperTest.java        | 164 +++++++++++++++
 5 files changed, 393 insertions(+), 206 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d5414d26/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
index 7f5dfdb..261ace0 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/XenServer610Resource.java
@@ -30,28 +30,18 @@ import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
-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.storage.MigrateVolumeAnswer;
 import com.cloud.agent.api.storage.MigrateVolumeCommand;
 import com.cloud.agent.api.to.DiskTO;
-import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
-import com.cloud.agent.api.to.VolumeTO;
-import com.cloud.network.Networks.TrafficType;
 import com.cloud.resource.ServerResource;
 import com.cloud.storage.Volume;
 import com.cloud.utils.exception.CloudRuntimeException;
 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;
@@ -68,11 +58,7 @@ public class XenServer610Resource extends XenServer600Resource {
 
     @Override
     public Answer executeRequest(final Command cmd) {
-        if (cmd instanceof MigrateWithStorageReceiveCommand) {
-            return execute((MigrateWithStorageReceiveCommand)cmd);
-        } else if (cmd instanceof MigrateWithStorageSendCommand) {
-            return execute((MigrateWithStorageSendCommand)cmd);
-        } else if (cmd instanceof MigrateWithStorageCompleteCommand) {
+        if (cmd instanceof MigrateWithStorageCompleteCommand) {
             return execute((MigrateWithStorageCompleteCommand)cmd);
         } else if (cmd instanceof MigrateVolumeCommand) {
             return execute((MigrateVolumeCommand)cmd);
@@ -116,197 +102,6 @@ public class XenServer610Resource extends XenServer600Resource {
         return volumeToList;
     }
 
-    protected MigrateWithStorageAnswer execute(final MigrateWithStorageCommand cmd) {
-        final Connection connection = getConnection();
-        final VirtualMachineTO vmSpec = cmd.getVirtualMachine();
-        final Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
-        final String vmName = vmSpec.getName();
-        Task task = null;
-
-        try {
-            prepareISO(connection, vmSpec.getName());
-
-            // Get the list of networks and recreate VLAN, if required.
-            for (final NicTO nicTo : vmSpec.getNics()) {
-                getNetwork(connection, nicTo);
-            }
-
-            final Map<String, String> other = new HashMap<String, String>();
-            other.put("live", "true");
-            final Network networkForSm = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
-            final Host host = Host.getByUuid(connection, _host.getUuid());
-            final Map<String, String> token = host.migrateReceive(connection, networkForSm, other);
-
-            // Get the vm to migrate.
-            final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
-            final 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.
-            final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
-            final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
-            for (final 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
-                final long timeout = _migratewait * 1000L;
-                waitForTask(connection, task, 1000, timeout);
-                checkForSuccess(connection, task);
-            } catch (final 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.
-                final long timeout = _migratewait * 1000L;
-                waitForTask(connection, task, 1000, timeout);
-                checkForSuccess(connection, task);
-            } catch (final 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.
-            final List<VolumeObjectTO> volumeToList = getUpdatedVolumePathsOfMigratedVm(connection, vmToMigrate, vmSpec.getDisks());
-            vmToMigrate.setAffinity(connection, host);
-            return new MigrateWithStorageAnswer(cmd, volumeToList);
-        } catch (final 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 (final Exception e) {
-                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.getUuid() + " due to " + e.toString());
-                }
-            }
-        }
-    }
-
-    protected MigrateWithStorageReceiveAnswer execute(final MigrateWithStorageReceiveCommand cmd) {
-        final Connection connection = getConnection();
-        final VirtualMachineTO vmSpec = cmd.getVirtualMachine();
-        final Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
-
-        try {
-            // Get a map of all the SRs to which the vdis will be migrated.
-            final Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
-            for (final Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
-                final SR sr = getStorageRepository(connection, entry.getValue().getUuid());
-                volumeToSr.put(entry.getKey(), sr);
-            }
-
-            // Get the list of networks to which the vifs will attach.
-            final Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
-            for (final NicTO nicTo : vmSpec.getNics()) {
-                final Network network = getNetwork(connection, nicTo);
-                nicToNetwork.put(nicTo, network);
-            }
-
-            final Map<String, String> other = new HashMap<String, String>();
-            other.put("live", "true");
-            final Network network = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
-            final Host host = Host.getByUuid(connection, _host.getUuid());
-            final Map<String, String> token = host.migrateReceive(connection, network, other);
-
-            return new MigrateWithStorageReceiveAnswer(cmd, volumeToSr, nicToNetwork, token);
-        } catch (final CloudRuntimeException e) {
-            s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
-            return new MigrateWithStorageReceiveAnswer(cmd, e);
-        } catch (final 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(final MigrateWithStorageSendCommand cmd) {
-        final Connection connection = getConnection();
-        final VirtualMachineTO vmSpec = cmd.getVirtualMachine();
-        final Map<VolumeTO, Object> volumeToSr = cmd.getVolumeToSr();
-        final Map<NicTO, Object> nicToNetwork = cmd.getNicToNetwork();
-        final Map<String, String> token = cmd.getToken();
-        final String vmName = vmSpec.getName();
-        final Set<VolumeTO> volumeToSet = null;
-        Task task = null;
-        try {
-            final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
-            final VM vmToMigrate = vms.iterator().next();
-            final 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.
-            final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
-            for (final Map.Entry<VolumeTO, Object> entry : volumeToSr.entrySet()) {
-                if (entry.getValue() instanceof SR) {
-                    final SR sr = (SR)entry.getValue();
-                    final 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.
-            final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
-            for (final Map.Entry<NicTO, Object> entry : nicToNetwork.entrySet()) {
-                if (entry.getValue() instanceof Network) {
-                    final Network network = (Network)entry.getValue();
-                    final 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.
-                final long timeout = _migratewait * 1000L;
-                waitForTask(connection, task, 1000, timeout);
-                checkForSuccess(connection, task);
-            } catch (final 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.
-                final long timeout = _migratewait * 1000L;
-                waitForTask(connection, task, 1000, timeout);
-                checkForSuccess(connection, task);
-            } catch (final Types.HandleInvalid e) {
-                s_logger.error("Error while migrating vm " + vmName, e);
-                throw new CloudRuntimeException("Error while migrating vm " + vmName, e);
-            }
-
-            return new MigrateWithStorageSendAnswer(cmd, volumeToSet);
-        } catch (final CloudRuntimeException e) {
-            s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
-            return new MigrateWithStorageSendAnswer(cmd, e);
-        } catch (final 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 (final Exception e) {
-                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.getUuid() + " due to " + e.toString());
-                }
-            }
-        }
-    }
-
     protected MigrateWithStorageCompleteAnswer execute(final MigrateWithStorageCompleteCommand cmd) {
         final Connection connection = getConnection();
         final VirtualMachineTO vmSpec = cmd.getVirtualMachine();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d5414d26/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
index e89d926..b0376c7 100644
--- a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/CitrixRequestWrapper.java
@@ -45,7 +45,9 @@ import com.cloud.agent.api.GetVncPortCommand;
 import com.cloud.agent.api.MaintainCommand;
 import com.cloud.agent.api.MigrateCommand;
 import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
 import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
 import com.cloud.agent.api.ModifySshKeysCommand;
 import com.cloud.agent.api.ModifyStoragePoolCommand;
 import com.cloud.agent.api.NetworkRulesSystemVmCommand;
@@ -197,6 +199,8 @@ public class CitrixRequestWrapper extends RequestWrapper {
         final Hashtable<Class<? extends Command>, CommandWrapper> xenServer610Commands = new Hashtable<Class<? extends Command>, CommandWrapper>();
         xenServer610Commands.put(MigrateWithStorageCommand.class, new XenServer610MigrateWithStorageCommandWrapper());
         xenServer610Commands.put(MigrateWithStorageReceiveCommand.class, new XenServer610MigrateWithStorageReceiveCommandWrapper());
+        xenServer610Commands.put(MigrateWithStorageSendCommand.class, new XenServer610MigrateWithStorageSendCommandWrapper());
+        xenServer610Commands.put(MigrateWithStorageCompleteCommand.class, new XenServer610MigrateWithStorageCompleteCommandWrapper());
         resources.put(XenServer610Resource.class, xenServer610Commands);
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d5414d26/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCompleteCommandWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCompleteCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCompleteCommandWrapper.java
new file mode 100644
index 0000000..e993b96
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageCompleteCommandWrapper.java
@@ -0,0 +1,81 @@
+//
+// 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 com.cloud.hypervisor.xenserver.resource.wrapper;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
+import com.cloud.hypervisor.xenserver.resource.XsHost;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.VM;
+
+public final class XenServer610MigrateWithStorageCompleteCommandWrapper extends CommandWrapper<MigrateWithStorageCompleteCommand, Answer, XenServer610Resource> {
+
+    private static final Logger s_logger = Logger.getLogger(XenServer610MigrateWithStorageCompleteCommandWrapper.class);
+
+    @Override
+    public Answer execute(final MigrateWithStorageCompleteCommand command, final XenServer610Resource xenServer610Resource) {
+        final Connection connection = xenServer610Resource.getConnection();
+        final VirtualMachineTO vmSpec = command.getVirtualMachine();
+
+        final String name = vmSpec.getName();
+        try {
+            final XsHost xsHost = xenServer610Resource.getHost();
+            final String uuid = xsHost.getUuid();
+
+            final Set<VM> vms = VM.getByNameLabel(connection, name);
+            // Check if VMs can be found by label.
+            if (vms == null) {
+                throw new CloudRuntimeException("Couldn't find VMs by label " + name + " on the destination host.");
+            }
+            final 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 " + name + " on the destination host.");
+            }
+
+            final Host host = Host.getByUuid(connection, uuid);
+            migratedVm.setAffinity(connection, host);
+
+            // Volume paths would have changed. Return that information.
+            final List<VolumeObjectTO> volumeToSet = xenServer610Resource.getUpdatedVolumePathsOfMigratedVm(connection, migratedVm, vmSpec.getDisks());
+
+            return new MigrateWithStorageCompleteAnswer(command, volumeToSet);
+        } catch (final CloudRuntimeException e) {
+            s_logger.error("Migration of vm " + name + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageCompleteAnswer(command, e);
+        } catch (final Exception e) {
+            s_logger.error("Migration of vm " + name + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageCompleteAnswer(command, e);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d5414d26/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageSendCommandWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageSendCommandWrapper.java b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageSendCommandWrapper.java
new file mode 100644
index 0000000..267f528
--- /dev/null
+++ b/plugins/hypervisors/xenserver/src/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610MigrateWithStorageSendCommandWrapper.java
@@ -0,0 +1,143 @@
+//
+// 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 com.cloud.hypervisor.xenserver.resource.wrapper;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.to.NicTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.hypervisor.xenserver.resource.XenServer610Resource;
+import com.cloud.resource.CommandWrapper;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Network;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Task;
+import com.xensource.xenapi.Types;
+import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VIF;
+import com.xensource.xenapi.VM;
+
+public final class XenServer610MigrateWithStorageSendCommandWrapper extends CommandWrapper<MigrateWithStorageSendCommand, Answer, XenServer610Resource> {
+
+    private static final Logger s_logger = Logger.getLogger(XenServer610MigrateWithStorageSendCommandWrapper.class);
+
+    @Override
+    public Answer execute(final MigrateWithStorageSendCommand command, final XenServer610Resource xenServer610Resource) {
+        final Connection connection = xenServer610Resource.getConnection();
+
+        final VirtualMachineTO vmSpec = command.getVirtualMachine();
+        final Map<VolumeTO, Object> volumeToSr = command.getVolumeToSr();
+        final Map<NicTO, Object> nicToNetwork = command.getNicToNetwork();
+        final Map<String, String> token = command.getToken();
+        final String vmName = vmSpec.getName();
+
+        Task task = null;
+        try {
+
+            final 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.
+            final Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+            for (final Map.Entry<VolumeTO, Object> entry : volumeToSr.entrySet()) {
+                final Object srObj = entry.getValue();
+                if (srObj instanceof SR) {
+                    final SR sr = (SR) srObj;
+                    final VolumeTO volume = entry.getKey();
+                    final VDI vdi = xenServer610Resource.getVDIbyUuid(connection, volume.getPath());
+                    vdiMap.put(vdi, sr);
+                } else {
+                    throw new CloudRuntimeException("The object " + srObj + " passed is not of type SR.");
+                }
+            }
+
+            final Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+            VM vmToMigrate = null;
+            if (vms != null) {
+                vmToMigrate = vms.iterator().next();
+            }
+
+            // Create the vif map.
+            final Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+            for (final Map.Entry<NicTO, Object> entry : nicToNetwork.entrySet()) {
+                Object networkObj = entry.getValue();
+                if (networkObj instanceof Network) {
+                    final Network network = (Network) networkObj;
+                    NicTO nic = entry.getKey();
+                    final VIF vif = xenServer610Resource.getVifByMac(connection, vmToMigrate, nic.getMac());
+                    vifMap.put(vif, network);
+                } else {
+                    throw new CloudRuntimeException("The object " + networkObj + " 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.
+                final long timeout = xenServer610Resource.getMigrateWait() * 1000L;
+                xenServer610Resource.waitForTask(connection, task, 1000, timeout);
+                xenServer610Resource.checkForSuccess(connection, task);
+            } catch (final 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.
+                final long timeout = xenServer610Resource.getMigrateWait() * 1000L;
+                xenServer610Resource.waitForTask(connection, task, 1000, timeout);
+                xenServer610Resource.checkForSuccess(connection, task);
+            } catch (final Types.HandleInvalid e) {
+                s_logger.error("Error while migrating vm " + vmName, e);
+                throw new CloudRuntimeException("Error while migrating vm " + vmName, e);
+            }
+
+            final Set<VolumeTO> volumeToSet = null;
+            return new MigrateWithStorageSendAnswer(command, volumeToSet);
+        } catch (final CloudRuntimeException e) {
+            s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageSendAnswer(command, e);
+        } catch (final Exception e) {
+            s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageSendAnswer(command, e);
+        } finally {
+            if (task != null) {
+                try {
+                    task.destroy(connection);
+                } catch (final Exception e) {
+                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + xenServer610Resource.getHost().getUuid() + " due to " + e.toString());
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d5414d26/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
index 649dd1f..7f17ed4 100644
--- a/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
+++ b/plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/wrapper/XenServer610WrapperTest.java
@@ -40,6 +40,7 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.CheckNetworkCommand;
 import com.cloud.agent.api.MigrateWithStorageCommand;
 import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
 import com.cloud.agent.api.SetupCommand;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.StorageFilerTO;
@@ -56,6 +57,7 @@ import com.xensource.xenapi.Network;
 import com.xensource.xenapi.SR;
 import com.xensource.xenapi.Types.XenAPIException;
 import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VIF;
 
 @RunWith(PowerMockRunner.class)
 public class XenServer610WrapperTest {
@@ -269,4 +271,166 @@ public class XenServer610WrapperTest {
 
         assertFalse(answer.getResult());
     }
+
+    @Test
+    public void testMigrateWithStorageSendCommand() {
+        final String vmName = "small";
+        final String path = "/";
+        final String mac = "3c:15:c2:c4:4f:18";
+
+        final Connection conn = Mockito.mock(Connection.class);
+        final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
+
+        final VolumeTO volume1 = Mockito.mock(VolumeTO.class);
+        final VolumeTO volume2 = Mockito.mock(VolumeTO.class);
+
+        final SR sr1 = Mockito.mock(SR.class);
+        final SR sr2 = Mockito.mock(SR.class);
+
+        final VDI vdi1 = Mockito.mock(VDI.class);
+        final VDI vdi2 = Mockito.mock(VDI.class);
+
+        final NicTO nic1 = Mockito.mock(NicTO.class);
+        final NicTO nic2 = Mockito.mock(NicTO.class);
+
+        final Network network1 = Mockito.mock(Network.class);
+        final Network network2 = Mockito.mock(Network.class);
+
+        final Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
+        volumeToSr.put(volume1, sr1);
+        volumeToSr.put(volume2, sr2);
+
+        final Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
+        nicToNetwork.put(nic1, network1);
+        nicToNetwork.put(nic2, network2);
+
+        final Map<String, String> token = new HashMap<String, String>();
+
+        final VIF vif1 = Mockito.mock(VIF.class);
+        final VIF vif2 = Mockito.mock(VIF.class);
+
+        final MigrateWithStorageSendCommand migrateStorageCommand = new MigrateWithStorageSendCommand(vmSpec, volumeToSr, nicToNetwork, token);
+
+        final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
+        assertNotNull(wrapper);
+
+        when(xenServer610Resource.getConnection()).thenReturn(conn);
+        when(vmSpec.getName()).thenReturn(vmName);
+
+        when(volume1.getPath()).thenReturn(path);
+        when(volume2.getPath()).thenReturn(path);
+
+        when(nic1.getMac()).thenReturn(mac);
+        when(nic2.getMac()).thenReturn(mac);
+
+        when(xenServer610Resource.getVDIbyUuid(conn, volume1.getPath())).thenReturn(vdi1);
+        when(xenServer610Resource.getVDIbyUuid(conn, volume2.getPath())).thenReturn(vdi2);
+
+        try {
+            when(xenServer610Resource.getVifByMac(conn, null, nic1.getMac())).thenReturn(vif1);
+            when(xenServer610Resource.getVifByMac(conn, null, nic2.getMac())).thenReturn(vif2);
+        } catch (final XenAPIException e) {
+            fail(e.getMessage());
+        } catch (final XmlRpcException e) {
+            fail(e.getMessage());
+        }
+
+        final Answer answer = wrapper.execute(migrateStorageCommand, xenServer610Resource);
+
+        verify(xenServer610Resource, times(1)).getConnection();
+
+        try {
+            verify(xenServer610Resource, times(2)).getVDIbyUuid(conn, volume1.getPath());
+            verify(xenServer610Resource, times(2)).getVifByMac(conn, null, nic1.getMac());
+        } catch (final XenAPIException e) {
+            fail(e.getMessage());
+        } catch (final XmlRpcException e) {
+            fail(e.getMessage());
+        }
+
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testMigrateWithStorageSendCommandSRException() {
+        final String vmName = "small";
+
+        final Connection conn = Mockito.mock(Connection.class);
+        final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
+
+        final VolumeTO volume1 = Mockito.mock(VolumeTO.class);
+        final VolumeTO volume2 = Mockito.mock(VolumeTO.class);
+
+        final Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
+        volumeToSr.put(volume1, new String("a"));
+        volumeToSr.put(volume2, new String("b"));
+
+        final Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
+        final Map<String, String> token = new HashMap<String, String>();
+
+        final MigrateWithStorageSendCommand migrateStorageCommand = new MigrateWithStorageSendCommand(vmSpec, volumeToSr, nicToNetwork, token);
+
+        final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
+        assertNotNull(wrapper);
+
+        when(xenServer610Resource.getConnection()).thenReturn(conn);
+        when(vmSpec.getName()).thenReturn(vmName);
+
+        final Answer answer = wrapper.execute(migrateStorageCommand, xenServer610Resource);
+
+        verify(xenServer610Resource, times(1)).getConnection();
+
+        assertFalse(answer.getResult());
+    }
+
+    @Test
+    public void testMigrateWithStorageSendCommandNetException() {
+        final String vmName = "small";
+        final String path = "/";
+
+        final Connection conn = Mockito.mock(Connection.class);
+        final VirtualMachineTO vmSpec = Mockito.mock(VirtualMachineTO.class);
+
+        final VolumeTO volume1 = Mockito.mock(VolumeTO.class);
+        final VolumeTO volume2 = Mockito.mock(VolumeTO.class);
+
+        final SR sr1 = Mockito.mock(SR.class);
+        final SR sr2 = Mockito.mock(SR.class);
+
+        final VDI vdi1 = Mockito.mock(VDI.class);
+        final VDI vdi2 = Mockito.mock(VDI.class);
+
+        final NicTO nic1 = Mockito.mock(NicTO.class);
+        final NicTO nic2 = Mockito.mock(NicTO.class);
+
+        final Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
+        volumeToSr.put(volume1, sr1);
+        volumeToSr.put(volume2, sr2);
+
+        final Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
+        nicToNetwork.put(nic1, new String("a"));
+        nicToNetwork.put(nic2, new String("b"));
+
+        final Map<String, String> token = new HashMap<String, String>();
+
+        final MigrateWithStorageSendCommand migrateStorageCommand = new MigrateWithStorageSendCommand(vmSpec, volumeToSr, nicToNetwork, token);
+
+        final CitrixRequestWrapper wrapper = CitrixRequestWrapper.getInstance();
+        assertNotNull(wrapper);
+
+        when(xenServer610Resource.getConnection()).thenReturn(conn);
+        when(vmSpec.getName()).thenReturn(vmName);
+
+        when(volume1.getPath()).thenReturn(path);
+        when(volume2.getPath()).thenReturn(path);
+
+        when(xenServer610Resource.getVDIbyUuid(conn, volume1.getPath())).thenReturn(vdi1);
+        when(xenServer610Resource.getVDIbyUuid(conn, volume2.getPath())).thenReturn(vdi2);
+
+        final Answer answer = wrapper.execute(migrateStorageCommand, xenServer610Resource);
+
+        verify(xenServer610Resource, times(1)).getConnection();
+
+        assertFalse(answer.getResult());
+    }
 }
\ No newline at end of file