You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ts...@apache.org on 2013/04/19 13:28:42 UTC

[28/35] git commit: updated refs/heads/marvin_refactor to 4abd929

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 changes are integrated into the latest storage refactoring changes. 3. Added the implementation for findHostsForMigration api. It lists the hosts to which an instance can be migrated, including hosts from within and across clusters to which an instance may be migrated with storage motion. The work of migrating a volume of a running vm is also done in copyAsync. 4. Updated the listHosts api for backward compatibility. 5. Added the implementation for migrateVirtualMachineWithVolume api. It migrates an instance with its volumes within a cluster and also across clusters. Also introduced a new XenServerStorageMotionStrategy for migrating volumes of a vm. When a vm is being migrated with its volumes, the vm is put in migrating state and a request is
  send to the volume manager to migrate the vm and its volumes. Volume manager calls into the volume service which forwards the request to data motion service after moving all the volumes to migrating state. Data motion service enumerates the strategies and the request reaches the XenServerStorageMotionStrategy. It calls in to the resource to complete the operation. 6. Resolved an issue where storage xenmotion of 2nd VM created from the same template to a host was failing with duplicate_vm exception. Made changes to remove the mac_seed key value pair from other_config when vms are created. This is was storage motion to fail. 7. Updated the db upgrade schema script. 8. Added the right permissions in commands.properties 9. Marvin tests for testing storage motion. Following scenarios are tested. 9.1. A virtual machine is migrated to another host. Its volumes are also migrated to another storage pool. 9.2. Just the volumes of a vm are migrated to another storage pool while the vm continu
 es to run on the same host. 10. Unit tests for testing migration of a vm with its volumes.

Signed-off-by: Abhinandan Prateek <ap...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 21ce3befc8ea9e1a6de449a21499a50ff141a183
Parents: eae22d2
Author: Devdeep Singh <de...@gmail.com>
Authored: Mon Apr 15 11:42:18 2013 +0530
Committer: Abhinandan Prateek <ap...@apache.org>
Committed: Fri Apr 19 11:36:42 2013 +0530

----------------------------------------------------------------------
 .../cloud/agent/api/MigrateWithStorageAnswer.java  |   39 ++
 .../cloud/agent/api/MigrateWithStorageCommand.java |   45 ++
 .../api/MigrateWithStorageCompleteAnswer.java      |   38 ++
 .../api/MigrateWithStorageCompleteCommand.java     |   36 ++
 .../agent/api/MigrateWithStorageReceiveAnswer.java |   55 +++
 .../api/MigrateWithStorageReceiveCommand.java      |   45 ++
 .../agent/api/MigrateWithStorageSendAnswer.java    |   39 ++
 .../agent/api/MigrateWithStorageSendCommand.java   |   58 +++
 .../agent/api/storage/MigrateVolumeAnswer.java     |   38 ++
 .../agent/api/storage/MigrateVolumeCommand.java    |   51 ++
 .../cloud/hypervisor/HypervisorCapabilities.java   |    2 +
 api/src/com/cloud/server/ManagementService.java    |   19 +-
 api/src/com/cloud/vm/UserVmService.java            |   27 ++
 .../org/apache/cloudstack/api/ApiConstants.java    |    2 +
 .../apache/cloudstack/api/ResponseGenerator.java   |    6 +
 .../admin/host/FindHostsForMigrationCmd.java       |  107 +++++
 .../api/command/admin/host/ListHostsCmd.java       |    7 +-
 .../storage/FindStoragePoolsForMigrationCmd.java   |   98 ++++
 .../vm/MigrateVirtualMachineWithVolumeCmd.java     |  160 +++++++
 .../api/command/user/volume/MigrateVolumeCmd.java  |    8 +
 .../api/response/HostForMigrationResponse.java     |  365 +++++++++++++++
 .../cloudstack/api/response/HostResponse.java      |    1 -
 .../response/StoragePoolForMigrationResponse.java  |  248 ++++++++++
 .../api/response/StoragePoolResponse.java          |    3 -
 client/tomcatconf/applicationContext.xml.in        |    1 +
 client/tomcatconf/commands.properties.in           |    3 +
 .../cloud/hypervisor/HypervisorCapabilitiesVO.java |   24 +-
 .../api/storage/ObjectInDataStoreStateMachine.java |    2 +
 .../subsystem/api/storage/VolumeService.java       |    7 +-
 .../image/motion/DefaultImageMotionStrategy.java   |   18 +
 .../storage/test/MockStorageMotionStrategy.java    |   19 +
 .../storage/motion/AncientDataMotionStrategy.java  |   84 ++++-
 .../storage/motion/DataMotionService.java          |    9 +
 .../storage/motion/DataMotionServiceImpl.java      |   16 +
 .../storage/motion/DataMotionStrategy.java         |   10 +
 .../cloudstack/storage/volume/VolumeObject.java    |    2 +
 .../storage/volume/VolumeServiceImpl.java          |  166 +++++++-
 .../manager/allocator/impl/RandomAllocator.java    |   56 +++
 .../xen/resource/CitrixResourceBase.java           |    4 +-
 .../xen/resource/XenServer56FP1Resource.java       |    1 +
 .../xen/resource/XenServer610Resource.java         |  359 ++++++++++++++-
 .../motion/XenServerStorageMotionStrategy.java     |  239 ++++++++++
 .../agent/manager/allocator/HostAllocator.java     |   23 +-
 .../manager/allocator/impl/FirstFitAllocator.java  |   47 ++
 .../manager/allocator/impl/TestingAllocator.java   |    7 +
 server/src/com/cloud/api/ApiDBUtils.java           |   19 +
 server/src/com/cloud/api/ApiResponseHelper.java    |   27 +-
 .../com/cloud/api/query/ViewResponseHelper.java    |   37 ++
 .../src/com/cloud/api/query/dao/HostJoinDao.java   |    5 +
 .../com/cloud/api/query/dao/HostJoinDaoImpl.java   |  135 ++++++-
 .../cloud/api/query/dao/StoragePoolJoinDao.java    |    6 +
 .../api/query/dao/StoragePoolJoinDaoImpl.java      |   59 +++-
 .../src/com/cloud/server/ManagementServerImpl.java |  284 ++++++++++--
 server/src/com/cloud/storage/VolumeManager.java    |    8 +
 .../src/com/cloud/storage/VolumeManagerImpl.java   |  112 +++++-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  123 +++++
 server/src/com/cloud/vm/VirtualMachineManager.java |    4 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |  210 +++++++++-
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |    8 +
 .../cloud/vm/MockVirtualMachineManagerImpl.java    |   10 +
 .../cloud/vm/VirtualMachineManagerImplTest.java    |  231 +++++++++-
 setup/db/db/schema-410to420.sql                    |    2 +
 test/integration/component/test_storage_motion.py  |  298 ++++++++++++
 tools/marvin/marvin/integration/lib/base.py        |   22 +
 64 files changed, 4109 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageAnswer.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageAnswer.java b/api/src/com/cloud/agent/api/MigrateWithStorageAnswer.java
new file mode 100644
index 0000000..06aff32
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageAnswer.java
@@ -0,0 +1,39 @@
+// 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.agent.api;
+
+import java.util.List;
+import com.cloud.agent.api.to.VolumeTO;
+
+public class MigrateWithStorageAnswer extends Answer {
+
+    List<VolumeTO> volumeTos;
+
+    public MigrateWithStorageAnswer(MigrateWithStorageCommand cmd, Exception ex) {
+        super(cmd, ex);
+        volumeTos = null;
+    }
+
+    public MigrateWithStorageAnswer(MigrateWithStorageCommand cmd, List<VolumeTO> volumeTos) {
+        super(cmd, true, null);
+        this.volumeTos = volumeTos;
+    }
+
+    public List<VolumeTO> getVolumeTos() {
+        return volumeTos;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageCommand.java b/api/src/com/cloud/agent/api/MigrateWithStorageCommand.java
new file mode 100644
index 0000000..058aa15
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageCommand.java
@@ -0,0 +1,45 @@
+// 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.agent.api;
+
+import java.util.Map;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+
+public class MigrateWithStorageCommand extends Command {
+    VirtualMachineTO vm;
+    Map<VolumeTO, StorageFilerTO> volumeToFiler;
+
+    public MigrateWithStorageCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler) {
+        this.vm = vm;
+        this.volumeToFiler = volumeToFiler;
+    }
+
+    public VirtualMachineTO getVirtualMachine() {
+        return vm;
+    }
+
+    public Map<VolumeTO, StorageFilerTO> getVolumeToFiler() {
+        return volumeToFiler;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageCompleteAnswer.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageCompleteAnswer.java b/api/src/com/cloud/agent/api/MigrateWithStorageCompleteAnswer.java
new file mode 100644
index 0000000..920cf48
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageCompleteAnswer.java
@@ -0,0 +1,38 @@
+// 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.agent.api;
+
+import java.util.List;
+import com.cloud.agent.api.to.VolumeTO;
+
+public class MigrateWithStorageCompleteAnswer extends Answer {
+    List<VolumeTO> volumeTos;
+
+    public MigrateWithStorageCompleteAnswer(MigrateWithStorageCompleteCommand cmd, Exception ex) {
+        super(cmd, ex);
+        volumeTos = null;
+    }
+
+    public MigrateWithStorageCompleteAnswer(MigrateWithStorageCompleteCommand cmd, List<VolumeTO> volumeTos) {
+        super(cmd, true, null);
+        this.volumeTos = volumeTos;
+    }
+
+    public List<VolumeTO> getVolumeTos() {
+        return volumeTos;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageCompleteCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageCompleteCommand.java b/api/src/com/cloud/agent/api/MigrateWithStorageCompleteCommand.java
new file mode 100644
index 0000000..1303c07
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageCompleteCommand.java
@@ -0,0 +1,36 @@
+// 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.agent.api;
+
+import com.cloud.agent.api.to.VirtualMachineTO;
+
+public class MigrateWithStorageCompleteCommand extends Command {
+    VirtualMachineTO vm;
+
+    public MigrateWithStorageCompleteCommand(VirtualMachineTO vm) {
+        this.vm = vm;
+    }
+
+    public VirtualMachineTO getVirtualMachine() {
+        return vm;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return false;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java b/api/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java
new file mode 100644
index 0000000..3bf521c
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageReceiveAnswer.java
@@ -0,0 +1,55 @@
+// 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.agent.api;
+
+import java.util.Map;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.NicTO;
+
+public class MigrateWithStorageReceiveAnswer extends Answer {
+
+    Map<VolumeTO, Object> volumeToSr;
+    Map<NicTO, Object> nicToNetwork;
+    Map<String, String> token;
+
+    public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Exception ex) {
+        super(cmd, ex);
+        volumeToSr = null;
+        nicToNetwork = null;
+        token = null;
+    }
+
+    public MigrateWithStorageReceiveAnswer(MigrateWithStorageReceiveCommand cmd, Map<VolumeTO, Object> volumeToSr,
+            Map<NicTO, Object> nicToNetwork, Map<String, String> token) {
+        super(cmd, true, null);
+        this.volumeToSr = volumeToSr;
+        this.nicToNetwork = nicToNetwork;
+        this.token = token;
+    }
+
+    public Map<VolumeTO, Object> getVolumeToSr() {
+        return volumeToSr;
+    }
+
+    public Map<NicTO, Object> getNicToNetwork() {
+        return nicToNetwork;
+    }
+
+    public Map<String, String> getToken() {
+        return token;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java b/api/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java
new file mode 100644
index 0000000..df67405
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageReceiveCommand.java
@@ -0,0 +1,45 @@
+// 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.agent.api;
+
+import java.util.Map;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+
+public class MigrateWithStorageReceiveCommand extends Command {
+    VirtualMachineTO vm;
+    Map<VolumeTO, StorageFilerTO> volumeToFiler;
+
+    public MigrateWithStorageReceiveCommand(VirtualMachineTO vm, Map<VolumeTO, StorageFilerTO> volumeToFiler) {
+        this.vm = vm;
+        this.volumeToFiler = volumeToFiler;
+    }
+
+    public VirtualMachineTO getVirtualMachine() {
+        return vm;
+    }
+
+    public Map<VolumeTO, StorageFilerTO> getVolumeToFiler() {
+        return volumeToFiler;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageSendAnswer.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageSendAnswer.java b/api/src/com/cloud/agent/api/MigrateWithStorageSendAnswer.java
new file mode 100644
index 0000000..7cf641f
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageSendAnswer.java
@@ -0,0 +1,39 @@
+// 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.agent.api;
+
+import java.util.Set;
+import com.cloud.agent.api.to.VolumeTO;
+
+public class MigrateWithStorageSendAnswer extends Answer {
+
+    Set<VolumeTO> volumeToSet;
+
+    public MigrateWithStorageSendAnswer(MigrateWithStorageSendCommand cmd, Exception ex) {
+        super(cmd, ex);
+        volumeToSet = null;
+    }
+
+    public MigrateWithStorageSendAnswer(MigrateWithStorageSendCommand cmd, Set<VolumeTO> volumeToSet) {
+        super(cmd, true, null);
+        this.volumeToSet = volumeToSet;
+    }
+
+    public Set<VolumeTO> getVolumeToSet() {
+        return volumeToSet;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java b/api/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java
new file mode 100644
index 0000000..d10db30
--- /dev/null
+++ b/api/src/com/cloud/agent/api/MigrateWithStorageSendCommand.java
@@ -0,0 +1,58 @@
+// 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.agent.api;
+
+import java.util.Map;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.NicTO;
+
+public class MigrateWithStorageSendCommand extends Command {
+    VirtualMachineTO vm;
+    Map<VolumeTO, Object> volumeToSr;
+    Map<NicTO, Object> nicToNetwork;
+    Map<String, String> token;
+
+    public MigrateWithStorageSendCommand(VirtualMachineTO vm, Map<VolumeTO, Object> volumeToSr,
+            Map<NicTO, Object> nicToNetwork, Map<String, String> token) {
+        this.vm = vm;
+        this.volumeToSr = volumeToSr;
+        this.nicToNetwork = nicToNetwork;
+        this.token = token;
+    }
+
+    public VirtualMachineTO getVirtualMachine() {
+        return vm;
+    }
+
+    public Map<VolumeTO, Object> getVolumeToSr() {
+        return volumeToSr;
+    }
+
+    public Map<NicTO, Object> getNicToNetwork() {
+        return nicToNetwork;
+    }
+
+    public Map<String, String> getToken() {
+        return token;
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/storage/MigrateVolumeAnswer.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/storage/MigrateVolumeAnswer.java b/api/src/com/cloud/agent/api/storage/MigrateVolumeAnswer.java
new file mode 100644
index 0000000..d5efa95
--- /dev/null
+++ b/api/src/com/cloud/agent/api/storage/MigrateVolumeAnswer.java
@@ -0,0 +1,38 @@
+// 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.agent.api.storage;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+
+public class MigrateVolumeAnswer extends Answer {
+    private String volumePath;
+
+    public MigrateVolumeAnswer(Command command, boolean success, String details, String volumePath) {
+        super(command, success, details);
+        this.volumePath = volumePath;
+    }
+
+    public MigrateVolumeAnswer(Command command) {
+        super(command);
+        this.volumePath = null;
+    }
+
+    public String getVolumePath() {
+        return volumePath;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java b/api/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java
new file mode 100644
index 0000000..b82d848
--- /dev/null
+++ b/api/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java
@@ -0,0 +1,51 @@
+// 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.agent.api.storage;
+
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.storage.StoragePool;
+
+public class MigrateVolumeCommand extends Command {
+
+    long volumeId;
+    String volumePath;
+    StorageFilerTO pool;
+
+    public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool) {
+        this.volumeId = volumeId;
+        this.volumePath = volumePath;
+        this.pool = new StorageFilerTO(pool);
+    }
+
+    @Override
+    public boolean executeInSequence() {
+        return true;
+    }
+
+    public String getVolumePath() {
+        return volumePath;
+    }
+
+    public long getVolumeId() {
+        return volumeId;
+    }
+
+    public StorageFilerTO getPool() {
+        return pool;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/hypervisor/HypervisorCapabilities.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/hypervisor/HypervisorCapabilities.java b/api/src/com/cloud/hypervisor/HypervisorCapabilities.java
index aff81b0..c954750 100644
--- a/api/src/com/cloud/hypervisor/HypervisorCapabilities.java
+++ b/api/src/com/cloud/hypervisor/HypervisorCapabilities.java
@@ -52,4 +52,6 @@ public interface HypervisorCapabilities extends Identity, InternalIdentity{
      */
     Integer getMaxHostsPerCluster();
 
+    boolean isStorageMotionSupported();
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/server/ManagementService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/server/ManagementService.java b/api/src/com/cloud/server/ManagementService.java
index 460357b..2249407 100755
--- a/api/src/com/cloud/server/ManagementService.java
+++ b/api/src/com/cloud/server/ManagementService.java
@@ -75,9 +75,11 @@ import com.cloud.network.IpAddress;
 import com.cloud.org.Cluster;
 import com.cloud.storage.GuestOS;
 import com.cloud.storage.GuestOsCategory;
+import com.cloud.storage.StoragePool;
 import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.SSHKeyPair;
 import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
 import com.cloud.vm.InstanceGroup;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.Type;
@@ -388,10 +390,21 @@ public interface ManagementService {
      * @param Long
      *            vmId
      *            Id of The VM to migrate
-     * @return Pair<List<? extends Host>, List<? extends Host>> List of all Hosts in VM's cluster and list of Hosts with
-     *         enough capacity
+     * @return Ternary<List<? extends Host>, List<? extends Host>, Map<Host, Boolean>> List of all Hosts to which a VM
+     *         can be migrated, list of Hosts with enough capacity and hosts requiring storage motion for migration.
      */
-    Pair<Pair<List<? extends Host>, Integer>, List<? extends Host>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize);
+    Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> listHostsForMigrationOfVM(
+            Long vmId, Long startIndex, Long pageSize);
+
+    /**
+     * List storage pools for live migrating of a volume. The API returns list of all pools in the cluster to which the
+     * volume can be migrated. Current pool is not included in the list.
+     *
+     * @param Long volumeId
+     * @return Pair<List<? extends StoragePool>, List<? extends StoragePool>> List of storage pools in cluster and list
+     *         of pools with enough capacity.
+     */
+    Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(Long volumeId);
 
     String[] listEventTypes();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/com/cloud/vm/UserVmService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java
index d963b74..aa21136 100755
--- a/api/src/com/cloud/vm/UserVmService.java
+++ b/api/src/com/cloud/vm/UserVmService.java
@@ -405,6 +405,33 @@ public interface UserVmService {
      */
     VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
 
+    /**
+     * Migrate the given VM with its volumes to the destination host. The API returns the migrated VM if it succeeds.
+     * Only root admin can migrate a VM.
+     *
+     * @param destinationStorage
+     *            TODO
+     * @param Long
+     *            vmId of The VM to migrate
+     * @param Host
+     *            destinationHost to migrate the VM
+     * @param Map
+     *            A map of volume to which pool it should be migrated
+     *
+     * @return VirtualMachine migrated VM
+     * @throws ManagementServerException
+     *             in case we get error finding the VM or host or access errors or other internal errors.
+     * @throws ConcurrentOperationException
+     *             if there are multiple users working on the same VM.
+     * @throws ResourceUnavailableException
+     *             if the destination host to migrate the VM is not currently available.
+     * @throws VirtualMachineMigrationException
+     *             if the VM to be migrated is not in Running state
+     */
+    VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool)
+            throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,
+            VirtualMachineMigrationException;
+
     UserVm moveVMToUser(AssignVMCmd moveUserVMCmd) throws ResourceAllocationException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException;
 
     VirtualMachine vmStorageMigration(Long vmId, StoragePool destPool);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index 8c32bb3..edaaeb3 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -365,6 +365,8 @@ public class ApiConstants {
     public static final String HA_HOST = "hahost";
     public static final String CUSTOM_DISK_OFF_MAX_SIZE = "customdiskofferingmaxsize";
     public static final String DEFAULT_ZONE_ID = "defaultzoneid";
+    public static final String LIVE_MIGRATE = "livemigrate";
+    public static final String MIGRATE_TO = "migrateto";
     public static final String GUID = "guid";
     public static final String VSWITCH_TYPE_GUEST_TRAFFIC = "guestvswitchtype";
     public static final String VSWITCH_TYPE_PUBLIC_TRAFFIC = "publicvswitchtype";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/ResponseGenerator.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ResponseGenerator.java b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
index c0dd57e..a3aa9de 100644
--- a/api/src/org/apache/cloudstack/api/ResponseGenerator.java
+++ b/api/src/org/apache/cloudstack/api/ResponseGenerator.java
@@ -189,6 +189,10 @@ public interface ResponseGenerator {
 
     HostResponse createHostResponse(Host host);
 
+    HostForMigrationResponse createHostForMigrationResponse(Host host);
+
+    HostForMigrationResponse createHostForMigrationResponse(Host host, EnumSet<HostDetails> details);
+
     VlanIpRangeResponse createVlanIpRangeResponse(Vlan vlan);
 
     IPAddressResponse createIPAddressResponse(IpAddress ipAddress);
@@ -216,6 +220,8 @@ public interface ResponseGenerator {
 
     StoragePoolResponse createStoragePoolResponse(StoragePool pool);
 
+    StoragePoolForMigrationResponse createStoragePoolForMigrationResponse(StoragePool pool);
+
     ClusterResponse createClusterResponse(Cluster cluster, Boolean showCapacities);
 
     FirewallRuleResponse createPortForwardingRuleResponse(PortForwardingRule fwRule);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
new file mode 100644
index 0000000..e6e45cc
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/FindHostsForMigrationCmd.java
@@ -0,0 +1,107 @@
+// 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.api.command.admin.host;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import com.cloud.host.Host;
+import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
+
+@APICommand(name = "findHostsForMigration", description="Find hosts suitable for migrating a virtual machine.",
+    responseObject=HostForMigrationResponse.class)
+public class FindHostsForMigrationCmd extends BaseListCmd {
+    public static final Logger s_logger = Logger.getLogger(FindHostsForMigrationCmd.class.getName());
+
+    private static final String s_name = "findhostsformigrationresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType = UserVmResponse.class,
+            required=false, description="find hosts to which this VM can be migrated and flag the hosts with enough " +
+                "CPU/RAM to host the VM")
+    private Long virtualMachineId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getVirtualMachineId() {
+        return virtualMachineId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public void execute() {
+        ListResponse<HostForMigrationResponse> response = null;
+        Pair<List<? extends Host>,Integer> result;
+        List<? extends Host> hostsWithCapacity = new ArrayList<Host>();
+        Map<Host, Boolean> hostsRequiringStorageMotion;
+
+        Ternary<Pair<List<? extends Host>,Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
+                _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
+        result = hostsForMigration.first();
+        hostsWithCapacity = hostsForMigration.second();
+        hostsRequiringStorageMotion = hostsForMigration.third();
+
+        response = new ListResponse<HostForMigrationResponse>();
+        List<HostForMigrationResponse> hostResponses = new ArrayList<HostForMigrationResponse>();
+        for (Host host : result.first()) {
+            HostForMigrationResponse hostResponse = _responseGenerator.createHostForMigrationResponse(host);
+            Boolean suitableForMigration = false;
+            if (hostsWithCapacity.contains(host)) {
+                suitableForMigration = true;
+            }
+            hostResponse.setSuitableForMigration(suitableForMigration);
+
+            Boolean requiresStorageMotion = hostsRequiringStorageMotion.get(host);
+            if (requiresStorageMotion != null && requiresStorageMotion) {
+                hostResponse.setRequiresStorageMotion(true);
+            } else {
+                hostResponse.setRequiresStorageMotion(false);
+            }
+
+            hostResponse.setObjectName("host");
+            hostResponses.add(hostResponse);
+        }
+
+        response.setResponses(hostResponses, result.second());
+        response.setResponseName(getCommandName());
+        this.setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
index 29844c3..5ec7cf3 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/host/ListHostsCmd.java
@@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.admin.host;
 import java.util.ArrayList;
 import java.util.EnumSet;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
@@ -37,6 +38,7 @@ import com.cloud.async.AsyncJob;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.host.Host;
 import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
 
 @APICommand(name = "listHosts", description="Lists hosts.", responseObject=HostResponse.class)
 public class ListHostsCmd extends BaseListCmd {
@@ -170,8 +172,8 @@ public class ListHostsCmd extends BaseListCmd {
         } else {
             Pair<List<? extends Host>,Integer> result;
             List<? extends Host> hostsWithCapacity = new ArrayList<Host>();
-
-            Pair<Pair<List<? extends Host>,Integer>, List<? extends Host>> hostsForMigration = _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
+            Ternary<Pair<List<? extends Host>,Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigration =
+                    _mgr.listHostsForMigrationOfVM(getVirtualMachineId(), this.getStartIndex(), this.getPageSizeVal());
             result = hostsForMigration.first();
             hostsWithCapacity = hostsForMigration.second();
 
@@ -192,6 +194,5 @@ public class ListHostsCmd extends BaseListCmd {
         }
         response.setResponseName(getCommandName());
         this.setResponseObject(response);
-
     }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/command/admin/storage/FindStoragePoolsForMigrationCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/FindStoragePoolsForMigrationCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/FindStoragePoolsForMigrationCmd.java
new file mode 100644
index 0000000..37d007c
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/FindStoragePoolsForMigrationCmd.java
@@ -0,0 +1,98 @@
+// 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.api.command.admin.storage;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
+import org.apache.cloudstack.api.response.VolumeResponse;
+import com.cloud.async.AsyncJob;
+import com.cloud.storage.StoragePool;
+import com.cloud.utils.Pair;
+
+@APICommand(name = "findStoragePoolsForMigration", description="Lists storage pools available for migration of a volume.",
+    responseObject=StoragePoolForMigrationResponse.class)
+public class FindStoragePoolsForMigrationCmd extends BaseListCmd {
+    public static final Logger s_logger = Logger.getLogger(FindStoragePoolsForMigrationCmd.class.getName());
+
+    private static final String s_name = "findstoragepoolsformigrationresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = VolumeResponse.class, required=true,
+            description="the ID of the volume")
+    private Long id;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    public AsyncJob.Type getInstanceType() {
+        return AsyncJob.Type.StoragePool;
+    }
+
+    @Override
+    public void execute() {
+        Pair<List<? extends StoragePool>, List<? extends StoragePool>> pools =
+                _mgr.listStoragePoolsForMigrationOfVolume(getId());
+        ListResponse<StoragePoolForMigrationResponse> response = new ListResponse<StoragePoolForMigrationResponse>();
+        List<StoragePoolForMigrationResponse> poolResponses = new ArrayList<StoragePoolForMigrationResponse>();
+
+        List<? extends StoragePool> allPools = pools.first();
+        List<? extends StoragePool> suitablePoolList = pools.second();
+        for (StoragePool pool : allPools) {
+            StoragePoolForMigrationResponse poolResponse = _responseGenerator.createStoragePoolForMigrationResponse(pool);
+            Boolean suitableForMigration = false;
+            for (StoragePool suitablePool : suitablePoolList) {
+                if (suitablePool.getId() == pool.getId()) {
+                    suitableForMigration = true;
+                    break;
+                }
+            }
+            poolResponse.setSuitableForMigration(suitableForMigration);
+            poolResponse.setObjectName("storagepool");
+            poolResponses.add(poolResponse);
+        }
+
+        response.setResponses(poolResponses);
+        response.setResponseName(getCommandName());
+        this.setResponseObject(response);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
new file mode 100644
index 0000000..b1eaf11
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java
@@ -0,0 +1,160 @@
+// 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.api.command.admin.vm;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.cloudstack.api.*;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ManagementServerException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.host.Host;
+import com.cloud.storage.StoragePool;
+import com.cloud.user.Account;
+import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+import com.cloud.vm.VirtualMachine;
+
+@APICommand(name = "migrateVirtualMachineWithVolume", description="Attempts Migration of a VM with its volumes to a different host", responseObject=UserVmResponse.class)
+public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(MigrateVMCmd.class.getName());
+
+    private static final String s_name = "migratevirtualmachinewithvolumeresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.HOST_ID, type=CommandType.UUID, entityType=HostResponse.class,
+            required=true, description="Destination Host ID to migrate VM to.")
+    private Long hostId;
+
+    @Parameter(name=ApiConstants.VIRTUAL_MACHINE_ID, type=CommandType.UUID, entityType=UserVmResponse.class,
+            required=true, description="the ID of the virtual machine")
+    private Long virtualMachineId;
+
+    @Parameter(name = ApiConstants.MIGRATE_TO, type = CommandType.MAP, required=false,
+            description = "Map of pool to which each volume should be migrated (volume/pool pair)")
+    private Map migrateVolumeTo;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getHostId() {
+        return hostId;
+    }
+
+    public Long getVirtualMachineId() {
+        return virtualMachineId;
+    }
+
+    public Map<String, String> getVolumeToPool() {
+        Map<String, String> volumeToPoolMap = new HashMap<String, String>();
+        if (migrateVolumeTo != null && !migrateVolumeTo.isEmpty()) {
+            Collection<?> allValues = migrateVolumeTo.values();
+            Iterator<?> iter = allValues.iterator();
+            while (iter.hasNext()) {
+                HashMap<String, String> volumeToPool = (HashMap<String, String>) iter.next();
+                String volume = volumeToPool.get("volume");
+                String pool = volumeToPool.get("pool");
+                volumeToPoolMap.put(volume, pool);
+            }
+        }
+        return volumeToPoolMap;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        UserVm userVm = _entityMgr.findById(UserVm.class, getVirtualMachineId());
+        if (userVm != null) {
+            return userVm.getAccountId();
+        }
+
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_VM_MIGRATE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return  "Attempting to migrate VM Id: " + getVirtualMachineId() + " to host Id: "+ getHostId();
+    }
+
+    @Override
+    public void execute(){
+        UserVm userVm = _userVmService.getUserVm(getVirtualMachineId());
+        if (userVm == null) {
+            throw new InvalidParameterValueException("Unable to find the VM by id=" + getVirtualMachineId());
+        }
+
+        Host destinationHost = _resourceService.getHost(getHostId());
+        if (destinationHost == null) {
+            throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id =" + getHostId());
+        }
+
+        try{
+            VirtualMachine migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(),
+                    destinationHost, getVolumeToPool());
+            if (migratedVm != null) {
+                UserVmResponse response = _responseGenerator.createUserVmResponse("virtualmachine", (UserVm)migratedVm).get(0);
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vm");
+            }
+        } catch (ResourceUnavailableException ex) {
+            s_logger.warn("Exception: ", ex);
+            throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
+        } catch (ConcurrentOperationException e) {
+            s_logger.warn("Exception: ", e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        } catch (ManagementServerException e) {
+            s_logger.warn("Exception: ", e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        } catch (VirtualMachineMigrationException e) {
+            s_logger.warn("Exception: ", e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
index 287241a..ce40f0d 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java
@@ -47,6 +47,10 @@ public class MigrateVolumeCmd extends BaseAsyncCmd {
             required=true, description="destination storage pool ID to migrate the volume to")
     private Long storageId;
 
+    @Parameter(name=ApiConstants.LIVE_MIGRATE, type=CommandType.BOOLEAN, required=false,
+            description="if the volume should be live migrated when it is attached to a running vm")
+    private Boolean liveMigrate;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -58,6 +62,10 @@ public class MigrateVolumeCmd extends BaseAsyncCmd {
     public Long getStoragePoolId() {
         return storageId;
     }
+
+    public boolean isLiveMigrate() {
+        return (liveMigrate != null) ? liveMigrate : false;
+    }
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/response/HostForMigrationResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/HostForMigrationResponse.java b/api/src/org/apache/cloudstack/api/response/HostForMigrationResponse.java
new file mode 100644
index 0000000..fde2440
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/HostForMigrationResponse.java
@@ -0,0 +1,365 @@
+// 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.api.response;
+
+import java.util.Date;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.host.Host;
+import com.cloud.host.Status;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value=Host.class)
+public class HostForMigrationResponse extends BaseResponse {
+    @SerializedName(ApiConstants.ID) @Param(description="the ID of the host")
+    private String id;
+
+    @SerializedName(ApiConstants.NAME) @Param(description="the name of the host")
+    private String name;
+
+    @SerializedName(ApiConstants.STATE) @Param(description="the state of the host")
+    private Status state;
+
+    @SerializedName("disconnected") @Param(description="true if the host is disconnected. False otherwise.")
+    private Date disconnectedOn;
+
+    @SerializedName(ApiConstants.TYPE) @Param(description="the host type")
+    private Host.Type hostType;
+
+    @SerializedName("oscategoryid") @Param(description="the OS category ID of the host")
+    private String osCategoryId;
+
+    @SerializedName("oscategoryname") @Param(description="the OS category name of the host")
+    private String osCategoryName;
+
+    @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="the IP address of the host")
+    private String ipAddress;
+
+    @SerializedName(ApiConstants.ZONE_ID) @Param(description="the Zone ID of the host")
+    private String zoneId;
+
+    @SerializedName(ApiConstants.ZONE_NAME) @Param(description="the Zone name of the host")
+    private String zoneName;
+
+    @SerializedName(ApiConstants.POD_ID) @Param(description="the Pod ID of the host")
+    private String podId;
+
+    @SerializedName("podname") @Param(description="the Pod name of the host")
+    private String podName;
+
+    @SerializedName("version") @Param(description="the host version")
+    private String version;
+
+    @SerializedName(ApiConstants.HYPERVISOR) @Param(description="the host hypervisor")
+    private HypervisorType hypervisor;
+
+    @SerializedName("cpunumber") @Param(description="the CPU number of the host")
+    private Integer cpuNumber;
+
+    @SerializedName("cpuspeed") @Param(description="the CPU speed of the host")
+    private Long cpuSpeed;
+
+    @SerializedName("cpuallocated") @Param(description="the amount of the host's CPU currently allocated")
+    private String cpuAllocated;
+
+    @SerializedName("cpuused") @Param(description="the amount of the host's CPU currently used")
+    private String cpuUsed;
+
+    @SerializedName("cpuwithoverprovisioning") @Param(description="the amount of the host's CPU after applying the cpu.overprovisioning.factor ")
+    private String cpuWithOverprovisioning;
+
+    @SerializedName("averageload") @Param(description="the cpu average load on the host")
+    private Long averageLoad;
+
+    @SerializedName("networkkbsread") @Param(description="the incoming network traffic on the host")
+    private Long networkKbsRead;
+
+    @SerializedName("networkkbswrite") @Param(description="the outgoing network traffic on the host")
+    private Long networkKbsWrite;
+
+    @SerializedName("memorytotal") @Param(description="the memory total of the host")
+    private Long memoryTotal;
+
+    @SerializedName("memoryallocated") @Param(description="the amount of the host's memory currently allocated")
+    private Long memoryAllocated;
+
+    @SerializedName("memoryused") @Param(description="the amount of the host's memory currently used")
+    private Long memoryUsed;
+
+    @SerializedName("disksizetotal") @Param(description="the total disk size of the host")
+    private Long diskSizeTotal;
+
+    @SerializedName("disksizeallocated") @Param(description="the host's currently allocated disk size")
+    private Long diskSizeAllocated;
+
+    @SerializedName("capabilities") @Param(description="capabilities of the host")
+    private String capabilities;
+
+    @SerializedName("lastpinged") @Param(description="the date and time the host was last pinged")
+    private Date lastPinged;
+
+    @SerializedName("managementserverid") @Param(description="the management server ID of the host")
+    private Long managementServerId;
+
+    @SerializedName("clusterid") @Param(description="the cluster ID of the host")
+    private String clusterId;
+
+    @SerializedName("clustername") @Param(description="the cluster name of the host")
+    private String clusterName;
+
+    @SerializedName("clustertype") @Param(description="the cluster type of the cluster that host belongs to")
+    private String clusterType;
+
+    @SerializedName("islocalstorageactive") @Param(description="true if local storage is active, false otherwise")
+    private Boolean localStorageActive;
+
+    @SerializedName(ApiConstants.CREATED) @Param(description="the date and time the host was created")
+    private Date created;
+
+    @SerializedName("removed") @Param(description="the date and time the host was removed")
+    private Date removed;
+
+    @SerializedName("events") @Param(description="events available for the host")
+    private String events;
+
+    @SerializedName("hosttags") @Param(description="comma-separated list of tags for the host")
+    private String hostTags;
+
+    @SerializedName("hasenoughcapacity") @Param(description="true if this host has enough CPU and RAM capacity to migrate a VM to it, false otherwise")
+    private Boolean hasEnoughCapacity;
+
+    @SerializedName("suitableformigration") @Param(description="true if this host is suitable(has enough capacity and satisfies all conditions like hosttags, max guests vm limit etc) to migrate a VM to it , false otherwise")
+    private Boolean suitableForMigration;
+
+    @SerializedName("requiresStorageMotion") @Param(description="true if migrating a vm to this host requires storage motion, false otherwise")
+    private Boolean requiresStorageMotion;
+
+    @SerializedName("resourcestate") @Param(description="the resource state of the host")
+    private String resourceState;
+
+    @SerializedName(ApiConstants.HYPERVISOR_VERSION) @Param(description="the hypervisor version")
+    private String hypervisorVersion;
+
+    @SerializedName(ApiConstants.HA_HOST) @Param(description="true if the host is Ha host (dedicated to vms started by HA process; false otherwise")
+    private Boolean haHost;
+
+    @Override
+    public String getObjectId() {
+        return this.getId();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public void setState(Status state) {
+        this.state = state;
+    }
+
+    public void setDisconnectedOn(Date disconnectedOn) {
+        this.disconnectedOn = disconnectedOn;
+    }
+
+    public void setHostType(Host.Type hostType) {
+        this.hostType = hostType;
+    }
+
+    public void setOsCategoryId(String osCategoryId) {
+        this.osCategoryId = osCategoryId;
+    }
+
+    public void setOsCategoryName(String osCategoryName) {
+        this.osCategoryName = osCategoryName;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public void setZoneId(String zoneId) {
+        this.zoneId = zoneId;
+    }
+
+    public void setZoneName(String zoneName) {
+        this.zoneName = zoneName;
+    }
+
+    public void setPodId(String podId) {
+        this.podId = podId;
+    }
+
+    public void setPodName(String podName) {
+        this.podName = podName;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public void setHypervisor(HypervisorType hypervisor) {
+        this.hypervisor = hypervisor;
+    }
+
+    public void setCpuNumber(Integer cpuNumber) {
+        this.cpuNumber = cpuNumber;
+    }
+
+    public void setCpuSpeed(Long cpuSpeed) {
+        this.cpuSpeed = cpuSpeed;
+    }
+
+    public String getCpuAllocated() {
+        return cpuAllocated;
+    }
+
+    public void setCpuAllocated(String cpuAllocated) {
+        this.cpuAllocated = cpuAllocated;
+    }
+
+    public void setCpuUsed(String cpuUsed) {
+        this.cpuUsed = cpuUsed;
+    }
+
+    public void setAverageLoad(Long averageLoad) {
+        this.averageLoad = averageLoad;
+    }
+
+    public void setNetworkKbsRead(Long networkKbsRead) {
+        this.networkKbsRead = networkKbsRead;
+    }
+
+    public void setNetworkKbsWrite(Long networkKbsWrite) {
+        this.networkKbsWrite = networkKbsWrite;
+    }
+
+    public void setMemoryTotal(Long memoryTotal) {
+        this.memoryTotal = memoryTotal;
+    }
+
+    public void setMemoryAllocated(Long memoryAllocated) {
+        this.memoryAllocated = memoryAllocated;
+    }
+
+    public void setMemoryUsed(Long memoryUsed) {
+        this.memoryUsed = memoryUsed;
+    }
+
+    public void setDiskSizeTotal(Long diskSizeTotal) {
+        this.diskSizeTotal = diskSizeTotal;
+    }
+
+    public void setDiskSizeAllocated(Long diskSizeAllocated) {
+        this.diskSizeAllocated = diskSizeAllocated;
+    }
+
+    public void setCapabilities(String capabilities) {
+        this.capabilities = capabilities;
+    }
+
+    public void setLastPinged(Date lastPinged) {
+        this.lastPinged = lastPinged;
+    }
+
+    public void setManagementServerId(Long managementServerId) {
+        this.managementServerId = managementServerId;
+    }
+
+    public void setClusterId(String clusterId) {
+        this.clusterId = clusterId;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public void setClusterType(String clusterType) {
+        this.clusterType = clusterType;
+    }
+
+    public void setLocalStorageActive(Boolean localStorageActive) {
+        this.localStorageActive = localStorageActive;
+    }
+
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+    public void setRemoved(Date removed) {
+        this.removed = removed;
+    }
+
+    public void setEvents(String events) {
+        this.events = events;
+    }
+
+    public String getHostTags() {
+        return hostTags;
+    }
+
+    public void setHostTags(String hostTags) {
+        this.hostTags = hostTags;
+    }
+
+    public void setHasEnoughCapacity(Boolean hasEnoughCapacity) {
+        this.hasEnoughCapacity = hasEnoughCapacity;
+    }
+
+    public void setSuitableForMigration(Boolean suitableForMigration) {
+        this.suitableForMigration = suitableForMigration;
+    }
+
+    public void setRequiresStorageMotion(Boolean requiresStorageMotion) {
+        this.requiresStorageMotion = requiresStorageMotion;
+    }
+
+    public String getResourceState() {
+        return resourceState;
+    }
+
+    public void setResourceState(String resourceState) {
+        this.resourceState = resourceState;
+    }
+
+    public String getCpuWithOverprovisioning() {
+        return cpuWithOverprovisioning;
+    }
+
+    public void setCpuWithOverprovisioning(String cpuWithOverprovisioning) {
+        this.cpuWithOverprovisioning = cpuWithOverprovisioning;
+    }
+
+    public void setHypervisorVersion(String hypervisorVersion) {
+        this.hypervisorVersion = hypervisorVersion;
+    }
+
+    public void setHaHost(Boolean haHost) {
+        this.haHost = haHost;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/response/HostResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/HostResponse.java b/api/src/org/apache/cloudstack/api/response/HostResponse.java
index f5aa8f9..687687d 100644
--- a/api/src/org/apache/cloudstack/api/response/HostResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/HostResponse.java
@@ -330,7 +330,6 @@ public class HostResponse extends BaseResponse {
         this.hasEnoughCapacity = hasEnoughCapacity;
     }
 
-
     public void setSuitableForMigration(Boolean suitableForMigration) {
         this.suitableForMigration = suitableForMigration;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java
new file mode 100644
index 0000000..f0bbcb1
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/StoragePoolForMigrationResponse.java
@@ -0,0 +1,248 @@
+// 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.api.response;
+
+import java.util.Date;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.serializer.Param;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolStatus;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value=StoragePool.class)
+public class StoragePoolForMigrationResponse extends BaseResponse {
+    @SerializedName("id") @Param(description="the ID of the storage pool")
+    private String id;
+
+    @SerializedName("zoneid") @Param(description="the Zone ID of the storage pool")
+    private String zoneId;
+
+    @SerializedName(ApiConstants.ZONE_NAME) @Param(description="the Zone name of the storage pool")
+    private String zoneName;
+
+    @SerializedName("podid") @Param(description="the Pod ID of the storage pool")
+    private String podId;
+
+    @SerializedName("podname") @Param(description="the Pod name of the storage pool")
+    private String podName;
+
+    @SerializedName("name") @Param(description="the name of the storage pool")
+    private String name;
+
+    @SerializedName("ipaddress") @Param(description="the IP address of the storage pool")
+    private String ipAddress;
+
+    @SerializedName("path") @Param(description="the storage pool path")
+    private String path;
+
+    @SerializedName("created") @Param(description="the date and time the storage pool was created")
+    private Date created;
+
+    @SerializedName("type") @Param(description="the storage pool type")
+    private String type;
+
+    @SerializedName("clusterid") @Param(description="the ID of the cluster for the storage pool")
+    private String clusterId;
+
+    @SerializedName("clustername") @Param(description="the name of the cluster for the storage pool")
+    private String clusterName;
+
+    @SerializedName("disksizetotal") @Param(description="the total disk size of the storage pool")
+    private Long diskSizeTotal;
+
+    @SerializedName("disksizeallocated") @Param(description="the host's currently allocated disk size")
+    private Long diskSizeAllocated;
+
+    @SerializedName("disksizeused") @Param(description="the host's currently used disk size")
+    private Long diskSizeUsed;
+
+    @SerializedName("tags") @Param(description="the tags for the storage pool")
+    private String tags;
+
+    @SerializedName(ApiConstants.STATE) @Param(description="the state of the storage pool")
+    private StoragePoolStatus state;
+
+    @SerializedName(ApiConstants.SCOPE) @Param(description="the scope of the storage pool")
+    private String scope;
+
+    @SerializedName("suitableformigration") @Param(description="true if this pool is suitable to migrate a volume," +
+            " false otherwise")
+    private Boolean suitableForMigration;
+
+    /**
+     * @return the scope
+     */
+    public String getScope() {
+        return scope;
+    }
+
+    /**
+     * @param scope the scope to set
+     */
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+    @Override
+    public String getObjectId() {
+        return this.getId();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getZoneId() {
+        return zoneId;
+    }
+
+    public void setZoneId(String zoneId) {
+        this.zoneId = zoneId;
+    }
+
+    public String getZoneName() {
+        return zoneName;
+    }
+
+    public void setZoneName(String zoneName) {
+        this.zoneName = zoneName;
+    }
+
+    public String getPodId() {
+        return podId;
+    }
+
+    public void setPodId(String podId) {
+        this.podId = podId;
+    }
+
+    public String getPodName() {
+        return podName;
+    }
+
+    public void setPodName(String podName) {
+        this.podName = podName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public Date getCreated() {
+        return created;
+    }
+
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getClusterId() {
+        return clusterId;
+    }
+
+    public void setClusterId(String clusterId) {
+        this.clusterId = clusterId;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public Long getDiskSizeTotal() {
+        return diskSizeTotal;
+    }
+
+    public void setDiskSizeTotal(Long diskSizeTotal) {
+        this.diskSizeTotal = diskSizeTotal;
+    }
+
+    public Long getDiskSizeAllocated() {
+        return diskSizeAllocated;
+    }
+
+    public void setDiskSizeAllocated(Long diskSizeAllocated) {
+        this.diskSizeAllocated = diskSizeAllocated;
+    }
+
+    public Long getDiskSizeUsed() {
+        return diskSizeUsed;
+    }
+
+    public void setDiskSizeUsed(Long diskSizeUsed) {
+        this.diskSizeUsed = diskSizeUsed;
+    }
+
+    public String getTags() {
+        return tags;
+    }
+
+    public void setTags(String tags) {
+        this.tags = tags;
+    }
+
+    public StoragePoolStatus getState() {
+        return state;
+    }
+
+    public void setState(StoragePoolStatus state) {
+        this.state = state;
+    }
+
+    public void setSuitableForMigration(Boolean suitableForMigration) {
+        this.suitableForMigration = suitableForMigration;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
index 0b16226..e034b17 100644
--- a/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/StoragePoolResponse.java
@@ -83,8 +83,6 @@ public class StoragePoolResponse extends BaseResponse {
     @SerializedName(ApiConstants.SCOPE) @Param(description="the scope of the storage pool")
     private String scope;
 
-
-
     /**
      * @return the scope
      */
@@ -239,5 +237,4 @@ public class StoragePoolResponse extends BaseResponse {
     public void setState(StoragePoolStatus state) {
         this.state = state;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/client/tomcatconf/applicationContext.xml.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in
index 7487a5e..d2ea380 100644
--- a/client/tomcatconf/applicationContext.xml.in
+++ b/client/tomcatconf/applicationContext.xml.in
@@ -714,6 +714,7 @@
   <bean id="agentMonitor" class="com.cloud.agent.manager.AgentMonitor" />
   <bean id="alertGenerator" class="com.cloud.event.AlertGenerator" />
   <bean id="ancientDataMotionStrategy" class="org.apache.cloudstack.storage.motion.AncientDataMotionStrategy" />
+  <bean id="xenserverStorageMotionStrategy" class="org.apache.cloudstack.storage.motion.XenServerStorageMotionStrategy" />
   <bean id="ancientImageDataStoreProvider" class="org.apache.cloudstack.storage.image.store.AncientImageDataStoreProvider" />
   <bean id="ancientSnapshotStrategy" class="org.apache.cloudstack.storage.snapshot.strategy.AncientSnapshotStrategy" />
   <bean id="apiDBUtils" class="com.cloud.api.ApiDBUtils" />

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 10fcfe3..b49e1fb 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -69,6 +69,7 @@ changeServiceForVirtualMachine=15
 scaleVirtualMachine=15
 assignVirtualMachine=1
 migrateVirtualMachine=1
+migrateVirtualMachineWithVolume=1
 recoverVirtualMachine=7
 
 #### snapshot commands
@@ -254,6 +255,7 @@ deleteHost=3
 prepareHostForMaintenance=1
 cancelHostMaintenance=1
 listHosts=3
+findHostsForMigration=1
 addSecondaryStorage=1
 updateHostPassword=1
 
@@ -288,6 +290,7 @@ deleteStoragePool=1
 listClusters=3
 enableStorageMaintenance=1
 cancelStorageMaintenance=1
+findStoragePoolsForMigration=1
 
 #### security group commands
 createSecurityGroup=15

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java b/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java
index fafc0a3..6689066 100644
--- a/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java
+++ b/core/src/com/cloud/hypervisor/HypervisorCapabilitiesVO.java
@@ -64,16 +64,21 @@ public class HypervisorCapabilitiesVO implements HypervisorCapabilities {
 
     @Column(name="vm_snapshot_enabled")
     private Boolean vmSnapshotEnabled;
-    
+
+    @Column(name="storage_motion_supported")
+    private boolean storageMotionSupported;
+
     protected HypervisorCapabilitiesVO() {
     	this.uuid = UUID.randomUUID().toString();
     }
 
-    public HypervisorCapabilitiesVO(HypervisorType hypervisorType, String hypervisorVersion, Long maxGuestsLimit, boolean securityGroupEnabled) {
+    public HypervisorCapabilitiesVO(HypervisorType hypervisorType, String hypervisorVersion, Long maxGuestsLimit,
+            boolean securityGroupEnabled, boolean storageMotionSupported) {
         this.hypervisorType = hypervisorType;
         this.hypervisorVersion = hypervisorVersion;
         this.maxGuestsLimit = maxGuestsLimit;
         this.securityGroupEnabled = securityGroupEnabled;
+        this.storageMotionSupported = storageMotionSupported;
     	this.uuid = UUID.randomUUID().toString();
     }
 
@@ -135,6 +140,21 @@ public class HypervisorCapabilitiesVO implements HypervisorCapabilities {
         return maxGuestsLimit;
     }
 
+    /**
+     * @param storageMotionSupported
+     */
+    public void setStorageMotionSupported(boolean storageMotionSupported) {
+        this.storageMotionSupported = storageMotionSupported;
+    }
+
+    /**
+     * @return if storage motion is supported
+     */
+    @Override
+    public boolean isStorageMotionSupported() {
+        return storageMotionSupported;
+    }
+
 
     public long getId() {
         return id;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java
index f619ef4..94ae800 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java
@@ -28,6 +28,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject<ObjectInDataS
         Created("The object is created"),
         Ready("Template downloading is accomplished"),
         Copying("The object is being coping"),
+        Migrating("The object is being migrated"),
         Destroying("Template is destroying"),
         Destroyed("Template is destroyed"),
         Failed("Failed to download template");
@@ -49,6 +50,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject<ObjectInDataS
         OperationSuccessed,
         OperationFailed,
         CopyingRequested,
+        MigrationRequested,
         ResizeRequested,
         ExpungeRequested
         

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
index 102c471..3a1fe6a 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/VolumeService.java
@@ -18,11 +18,12 @@
  */
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
+import java.util.Map;
 import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
-
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.exception.ConcurrentOperationException;
-
+import com.cloud.host.Host;
 
 public interface VolumeService {
     
@@ -70,6 +71,8 @@ public interface VolumeService {
 
     AsyncCallFuture<VolumeApiResult> createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template);
     AsyncCallFuture<VolumeApiResult> copyVolume(VolumeInfo srcVolume, DataStore destStore);
+    AsyncCallFuture<VolumeApiResult> migrateVolume(VolumeInfo srcVolume, DataStore destStore);
+    AsyncCallFuture<CommandResult> migrateVolumes(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost);
 
     boolean destroyVolume(long volumeId) throws ConcurrentOperationException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java
index a70fd8a..1c21496 100644
--- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java
+++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java
@@ -18,12 +18,15 @@
  */
 package org.apache.cloudstack.storage.image.motion;
 
+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.EndPoint;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.framework.async.AsyncRpcConext;
@@ -33,6 +36,8 @@ import org.apache.cloudstack.storage.endpoint.EndPointSelector;
 import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
 
 //At least one of datastore is coming from image store or image cache store
 
@@ -96,6 +101,11 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
     }
 
     @Override
+    public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+        return false;
+    }
+
+    @Override
     public Void copyAsync(DataObject srcData, DataObject destData,
             AsyncCompletionCallback<CopyCommandResult> callback) {
         DataStore destStore = destData.getDataStore();
@@ -137,4 +147,12 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy {
         
     }
 
+    @Override
+    public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            AsyncCompletionCallback<CopyCommandResult> callback) {
+        CopyCommandResult result = new CopyCommandResult("", null);
+        result.setResult("not implemented");
+        callback.complete(result);
+        return null;
+    }
 }