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:15 UTC

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

Updated Branches:
  refs/heads/marvin_refactor 94b18c6e9 -> 4abd92922


CLOUDSTACK-2046: Primary Storage & Secondary Storage is max limit is set 0 with listResourceLimits API response as ROOT admin

Signed-off-by: Sateesh Chodapuneedi <sa...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 985b2aa88d4d02db98a2e9be7ac081e4efbff879
Parents: b12905b
Author: Sanjay Tripathi <sa...@citrix.com>
Authored: Wed Apr 17 12:03:47 2013 +0530
Committer: Sateesh Chodapuneedi <sa...@apache.org>
Committed: Thu Apr 18 05:26:00 2013 +0530

----------------------------------------------------------------------
 server/src/com/cloud/api/ApiResponseHelper.java |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/985b2aa8/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 819c88b..7629e5e 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -379,7 +379,7 @@ public class ApiResponseHelper implements ResponseGenerator {
             populateDomain(resourceLimitResponse, accountTemp.getDomainId());
         }
         resourceLimitResponse.setResourceType(Integer.valueOf(limit.getType().getOrdinal()).toString());
-        if(limit.getType() == ResourceType.primary_storage || limit.getType() == ResourceType.secondary_storage) {
+        if((limit.getType() == ResourceType.primary_storage || limit.getType() == ResourceType.secondary_storage) && limit.getMax() >= 0) {
             resourceLimitResponse.setMax((long) Math.ceil(limit.getMax()/ResourceType.bytesToGiB));
         } else {
             resourceLimitResponse.setMax(limit.getMax());


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

Posted by ts...@apache.org.
Dashboard UI: Fix unwanted line breaks on event/alert text


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

Branch: refs/heads/marvin_refactor
Commit: d51d596baa35755c65ea72925bf9d3c36808ed8d
Parents: 320cad3
Author: Brian Federle <br...@citrix.com>
Authored: Thu Apr 18 15:15:24 2013 -0700
Committer: Brian Federle <br...@citrix.com>
Committed: Thu Apr 18 15:15:24 2013 -0700

----------------------------------------------------------------------
 ui/css/cloudstack3.css |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d51d596b/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 2b6d497..18d86b7 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -4372,6 +4372,17 @@ Dialogs*/
   display: block;
   clear: both;
   font-size: 11px;
+  float: left;
+  height: 10px;
+  max-width: 287px;
+  margin-top: 1px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.dashboard.admin .dashboard-container.sub.alerts ul li p br {
+  display: none;
 }
 
 /*** User*/


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

Posted by ts...@apache.org.
CLOUDSTACK-2086 UI shows added NIC even if Actual NIC addition has failed


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

Branch: refs/heads/marvin_refactor
Commit: ca6873a9d0a7085d3cbcd1a6d12f78c4137edfb2
Parents: 4fd9212
Author: Mice Xia <mi...@tcloudcomputing.com>
Authored: Fri Apr 19 10:51:22 2013 +0800
Committer: Mice Xia <mi...@tcloudcomputing.com>
Committed: Fri Apr 19 10:52:00 2013 +0800

----------------------------------------------------------------------
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |   23 ++++++++++----
 1 files changed, 16 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ca6873a9/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index a53e380..19f4005 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -2537,13 +2537,22 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
             VirtualMachineGuru<VMInstanceVO> vmGuru = getVmGuru(vmVO);
 
             s_logger.debug("Plugging nic for vm " + vm + " in network " + network);
-            if (vmGuru.plugNic(network, nicTO, vmTO, context, dest)) {
-                s_logger.debug("Nic is plugged successfully for vm " + vm + " in network " + network + ". Vm  is a part of network now");
-                return nic;
-            } else {
-                s_logger.warn("Failed to plug nic to the vm " + vm + " in network " + network);
-                return null;
-            }
+            
+            boolean result = false;
+            try{
+                result = vmGuru.plugNic(network, nicTO, vmTO, context, dest);
+                if (result) {
+                    s_logger.debug("Nic is plugged successfully for vm " + vm + " in network " + network + ". Vm  is a part of network now");
+                    return nic;
+                } else {
+                    s_logger.warn("Failed to plug nic to the vm " + vm + " in network " + network);
+                    return null;
+                }                
+            }finally{
+                if(!result){
+                    _networkMgr.removeNic(vmProfile, _nicsDao.findById(nic.getId()));
+                }
+            }            
         } else if (vm.getState() == State.Stopped) {
             //1) allocate nic
             return _networkMgr.createNicForVm(network, requested, context, vmProfile, false);


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

Posted by ts...@apache.org.
CLOUDSTACK-2088. Dedicated Public IP Addresses per tenant. Guest Network in a project acquires IPs at random even from the IP ranges which are dedicated to other accounts.
Modified search to return only IP's belonging to system pool


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

Branch: refs/heads/marvin_refactor
Commit: f8d4a23343d963ec9d2b9eec8e29f965c2e2198d
Parents: 977162b
Author: Likitha Shetty <li...@citrix.com>
Authored: Fri Apr 19 07:00:26 2013 +0530
Committer: Likitha Shetty <li...@citrix.com>
Committed: Fri Apr 19 07:02:46 2013 +0530

----------------------------------------------------------------------
 server/src/com/cloud/dc/dao/VlanDao.java           |    2 +
 server/src/com/cloud/dc/dao/VlanDaoImpl.java       |   19 +++++++++++++++
 .../src/com/cloud/network/NetworkManagerImpl.java  |   16 ++++++++----
 3 files changed, 31 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f8d4a233/server/src/com/cloud/dc/dao/VlanDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/dc/dao/VlanDao.java b/server/src/com/cloud/dc/dao/VlanDao.java
old mode 100644
new mode 100755
index 6423688..cc82632
--- a/server/src/com/cloud/dc/dao/VlanDao.java
+++ b/server/src/com/cloud/dc/dao/VlanDao.java
@@ -50,4 +50,6 @@ public interface VlanDao extends GenericDao<VlanVO, Long> {
 	List<VlanVO> listVlansByNetworkId(long networkId);
 	
 	List<VlanVO> listVlansByPhysicalNetworkId(long physicalNetworkId);
+
+        List<VlanVO> listZoneWideNonDedicatedVlans(long zoneId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f8d4a233/server/src/com/cloud/dc/dao/VlanDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/dc/dao/VlanDaoImpl.java b/server/src/com/cloud/dc/dao/VlanDaoImpl.java
old mode 100644
new mode 100755
index c5a635f..100295b
--- a/server/src/com/cloud/dc/dao/VlanDaoImpl.java
+++ b/server/src/com/cloud/dc/dao/VlanDaoImpl.java
@@ -58,6 +58,9 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao
     protected SearchBuilder<VlanVO> ZoneVlanSearch;
     protected SearchBuilder<VlanVO> NetworkVlanSearch;
     protected SearchBuilder<VlanVO> PhysicalNetworkVlanSearch;
+    protected SearchBuilder<VlanVO> ZoneWideNonDedicatedVlanSearch;
+
+    protected SearchBuilder<AccountVlanMapVO> AccountVlanMapSearch;
 
     @Inject protected PodVlanMapDao _podVlanMapDao;
     @Inject protected AccountVlanMapDao _accountVlanMapDao;
@@ -198,6 +201,14 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao
         PodVlanSearch2.done();
         ZoneTypePodSearch.done();
 
+        ZoneWideNonDedicatedVlanSearch = createSearchBuilder();
+        ZoneWideNonDedicatedVlanSearch.and("zoneId", ZoneWideNonDedicatedVlanSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
+        AccountVlanMapSearch = _accountVlanMapDao.createSearchBuilder();
+        AccountVlanMapSearch.and("accountId", AccountVlanMapSearch.entity().getAccountId(), SearchCriteria.Op.NULL);
+        ZoneWideNonDedicatedVlanSearch.join("AccountVlanMapSearch", AccountVlanMapSearch, ZoneWideNonDedicatedVlanSearch.entity().getId(), AccountVlanMapSearch.entity().getVlanDbId(), JoinBuilder.JoinType.LEFTOUTER);
+        ZoneWideNonDedicatedVlanSearch.done();
+        AccountVlanMapSearch.done();
+
         return result;
     }
 
@@ -312,4 +323,12 @@ public class VlanDaoImpl extends GenericDaoBase<VlanVO, Long> implements VlanDao
         sc.setParameters("physicalNetworkId", physicalNetworkId);
         return listBy(sc);
     }	
+
+    @Override
+    public List<VlanVO> listZoneWideNonDedicatedVlans(long zoneId) {
+        SearchCriteria<VlanVO> sc = ZoneWideNonDedicatedVlanSearch.create();
+        sc.setParameters("ZoneWideNonDedicatedVlanSearch", "zoneId", zoneId);
+        return listBy(sc);
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f8d4a233/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 7332ef3..114402b 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -581,6 +581,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
         VlanType vlanType = VlanType.VirtualNetwork;
         boolean assign = false;
         boolean allocateFromDedicatedRange = false;
+        List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
+        List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
 
         if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
             // zone is of type DataCenter. See DataCenterVO.java.
@@ -615,18 +617,17 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
             txn.start();
 
             // If account has dedicated Public IP ranges, allocate IP from the dedicated range
-            List<Long> vlanDbIds = new ArrayList<Long>();
             List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(ipOwner.getId());
             for (AccountVlanMapVO map : maps) {
-                vlanDbIds.add(map.getVlanDbId());
+                dedicatedVlanDbIds.add(map.getVlanDbId());
             }
-            if (vlanDbIds != null && !vlanDbIds.isEmpty()) {
+            if (dedicatedVlanDbIds != null && !dedicatedVlanDbIds.isEmpty()) {
                 allocateFromDedicatedRange = true;
             }
 
             try {
                 if (allocateFromDedicatedRange) {
-                    ip = fetchNewPublicIp(zone.getId(), null, vlanDbIds, ipOwner, vlanType, null,
+                    ip = fetchNewPublicIp(zone.getId(), null, dedicatedVlanDbIds, ipOwner, vlanType, null,
                             false, assign, null, isSystem, null);
                 }
             } catch(InsufficientAddressCapacityException e) {
@@ -637,12 +638,15 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
             }
 
             if (!allocateFromDedicatedRange) {
-                ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null,
+                List<VlanVO> nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(zone.getId());
+                for (VlanVO nonDedicatedVlan : nonDedicatedVlans) {
+                    nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
+                }
+                ip = fetchNewPublicIp(zone.getId(), null, nonDedicatedVlanDbIds, ipOwner, vlanType, null, false, assign, null,
                        isSystem, null);
             }
 
             if (ip == null) {
-
                 InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException
                         ("Unable to find available public IP addresses", DataCenter.class, zone.getId());
                 ex.addProxyObject(ApiDBUtils.findZoneById(zone.getId()).getUuid());


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

Posted by ts...@apache.org.
CLOUDSTACK-2077:The updatePhysicalNetwork command fails to update the database


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

Branch: refs/heads/marvin_refactor
Commit: 34899f9b999e0d92573aa7b8872e07a111811b53
Parents: 96cf795
Author: Isaac Chiang <is...@gmail.com>
Authored: Thu Apr 18 21:19:00 2013 +0530
Committer: Pranav Saxena <pr...@citrix.com>
Committed: Thu Apr 18 21:19:00 2013 +0530

----------------------------------------------------------------------
 .../src/com/cloud/network/NetworkServiceImpl.java  |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/34899f9b/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index 12c6068..c4effc9 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -2445,10 +2445,6 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
                 network.setVnet(vnetString);
             }
 
-
-
-            _physicalNetworkDao.update(id, network);
-
             for (Pair<Integer, Integer> vnetToAdd : vnetsToAdd) {
                 s_logger.debug("Adding vnet range " + vnetToAdd.first() + "-" + vnetToAdd.second() + " for the physicalNetwork id= " + id + " and zone id=" + network.getDataCenterId()
                     + " as a part of updatePhysicalNetwork call");
@@ -2456,6 +2452,8 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
             }
         }
 
+        _physicalNetworkDao.update(id, network);
+
         return network;
     }
 


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

Posted by ts...@apache.org.
UI Plugin/module API: Fix load order, refactor

-Fixes issue with load order, where plugin's initialization function were not called
  in order of the list

-Refactor so that modules and plugins are loaded via the same block,
  to avoid redundant code

-Load modules before plugins


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

Branch: refs/heads/marvin_refactor
Commit: 73d87f1ad21c7312517f04038b54a0ec084a5d64
Parents: a51b566
Author: Brian Federle <br...@citrix.com>
Authored: Thu Apr 18 13:49:43 2013 -0700
Committer: Brian Federle <br...@citrix.com>
Committed: Thu Apr 18 13:59:20 2013 -0700

----------------------------------------------------------------------
 ui/scripts/plugins.js |   77 ++++++++++++++++++++------------------------
 1 files changed, 35 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73d87f1a/ui/scripts/plugins.js
----------------------------------------------------------------------
diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js
index 9d1991c..122f4a0 100644
--- a/ui/scripts/plugins.js
+++ b/ui/scripts/plugins.js
@@ -15,7 +15,9 @@
 // specific language governing permissions and limitations
 // under the License.
 (function($, cloudStack, require) {
-  if (!cloudStack.pluginAPI) cloudStack.pluginAPI = {};
+  if (!cloudStack.pluginAPI) {
+    cloudStack.pluginAPI = {};
+  }
 
   var loadCSS = function(path) {
     var $link = $('<link>');
@@ -40,7 +42,7 @@
           error: function(json) {
             args.error(parseXMLHttpResponse(json));
           }
-        })
+        });
       },
       addSection: function(section) {
         cloudStack.sections[section.id] = $.extend(section, {
@@ -58,49 +60,40 @@
     show: cloudStack.uiCustom.pluginListing
   };
 
-  // Load plugins
-  $(cloudStack.plugins).map(function(index, pluginID) {
-    var basePath = 'plugins/' + pluginID + '/';
-    var pluginJS = basePath + pluginID + '.js';
-    var configJS = basePath + 'config.js';
-    var pluginCSS = basePath + pluginID + '.css';
+  // Load
+  $(['modules', 'plugins']).each(function() {
+    var type = this;
+    var paths = $(cloudStack[type]).map(function(index, id) {
+      return type + '/' + id + '/' + id;
+    }).toArray();
 
-    require([pluginJS], function() {
-      require([configJS]);
-      loadCSS(pluginCSS);
+    // Load modules
+    require(
+      paths,
+      function() {
+        $(cloudStack[type]).map(function(index, id) {
+          var basePath = type + '/' + id + '/';
+          var css = basePath + id + '.css';
+          var configJS = type == 'plugins' ? basePath + 'config' : null;
 
-      // Execute plugin
-      cloudStack.plugins[pluginID](
-        $.extend(true, {}, cloudStack.pluginAPI, {
-          pluginAPI: {
-            extend: function(api) {
-              cloudStack.pluginAPI[pluginID] = api;
-            }
+          if (configJS) {
+            // Load config metadata
+            require([configJS]);
           }
-        })
-      );
-    });
-  });
-
-  // Load modules
-  $(cloudStack.modules).map(function(index, moduleID) {
-    var basePath = 'modules/' + moduleID + '/';
-    var moduleJS = basePath + moduleID + '.js';
-    var moduleCSS = basePath + moduleID + '.css';
-
-    require([moduleJS], function() {
-      loadCSS(moduleCSS);
 
-      // Execute module
-      cloudStack.modules[moduleID](
-        $.extend(true, {}, cloudStack.pluginAPI, {
-          pluginAPI: {
-            extend: function(api) {
-              cloudStack.pluginAPI[moduleID] = api;
-            }
-          }
-        })
-      );
-    });
+          // Execute module
+          cloudStack[type][id](
+            $.extend(true, {}, cloudStack.pluginAPI, {
+              pluginAPI: {
+                extend: function(api) {
+                  cloudStack.pluginAPI[id] = api;
+                }
+              }
+            })
+          );
+          loadCSS(css);
+        });
+      }
+    );
   });
 }(jQuery, cloudStack, require));


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

Posted by ts...@apache.org.
CLOUDSTACK-1786: While reserving IPs in guest network, if guestvmcidr is a subset of network cidr but not a subset of cidr, exception is thrown.

Signed-off-by: Sateesh Chodapuneedi <sa...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: ea893eaf338bfe914e1cb99517a8429128a64152
Parents: 21ce3be
Author: Saksham Srivastava <sa...@citrix.com>
Authored: Fri Mar 22 16:37:44 2013 +0530
Committer: Sateesh Chodapuneedi <sa...@apache.org>
Committed: Fri Apr 19 14:08:37 2013 +0530

----------------------------------------------------------------------
 .../src/com/cloud/network/NetworkServiceImpl.java  |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ea893eaf/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkServiceImpl.java b/server/src/com/cloud/network/NetworkServiceImpl.java
index c4effc9..878d2a8 100755
--- a/server/src/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/com/cloud/network/NetworkServiceImpl.java
@@ -1868,11 +1868,13 @@ public class NetworkServiceImpl extends ManagerBase implements  NetworkService {
 
             // If networkCidr is null it implies that there was no prior IP reservation, so the network cidr is network.getCidr()
             // But in case networkCidr is a non null value (IP reservation already exists), it implies network cidr is networkCidr
-            if (networkCidr != null && ! NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) {
+            if (networkCidr != null) {
+                if(! NetUtils.isNetworkAWithinNetworkB(guestVmCidr, networkCidr)) {
                     throw new InvalidParameterValueException ("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR  should be a subset of network CIDR : " + networkCidr);
+                }
             } else {
                 if (! NetUtils.isNetworkAWithinNetworkB(guestVmCidr, network.getCidr())) {
-                     throw new InvalidParameterValueException ("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR  should be a subset of network CIDR :  " + network.getCidr());
+                    throw new InvalidParameterValueException ("Invalid value of Guest VM CIDR. For IP Reservation, Guest VM CIDR  should be a subset of network CIDR :  " + network.getCidr());
                 }
             }
 


[27/35] 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 c

Posted by ts...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
index b619ee9..a84f308 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java
@@ -18,11 +18,18 @@
  */
 package org.apache.cloudstack.storage.test;
 
+import java.util.Map;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.storage.motion.DataMotionStrategy;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
 public class MockStorageMotionStrategy implements DataMotionStrategy {
 
     @Override
@@ -32,6 +39,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
     }
 
     @Override
+    public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+        return true;
+    }
+
+    @Override
     public Void copyAsync(DataObject srcData, DataObject destData,
             AsyncCompletionCallback<CopyCommandResult> callback) {
         CopyCommandResult result = new CopyCommandResult("something", null);
@@ -39,4 +51,11 @@ public class MockStorageMotionStrategy implements DataMotionStrategy {
         return null;
     }
 
+    @Override
+    public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            AsyncCompletionCallback<CopyCommandResult> callback) {
+        CopyCommandResult result = new CopyCommandResult("something", null);
+        callback.complete(result);
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 3602bb1..ad9238a 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -20,12 +20,14 @@ package org.apache.cloudstack.storage.motion;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -36,6 +38,7 @@ import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
+import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.BackupSnapshotAnswer;
 import com.cloud.agent.api.BackupSnapshotCommand;
@@ -47,15 +50,21 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
 import com.cloud.agent.api.UpgradeSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeAnswer;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
+import com.cloud.agent.api.storage.MigrateVolumeAnswer;
+import com.cloud.agent.api.storage.MigrateVolumeCommand;
 import com.cloud.agent.api.storage.CreateAnswer;
 import com.cloud.agent.api.storage.CreateCommand;
 import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.SwiftTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.OperationTimedoutException;
 import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.storage.DiskOfferingVO;
@@ -86,6 +95,8 @@ import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Transaction;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.DiskProfile;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
 
 @Component
 public class AncientDataMotionStrategy implements DataMotionStrategy {
@@ -102,8 +113,12 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
     @Inject
     StorageManager storageMgr;
     @Inject
+    AgentManager agentMgr;
+    @Inject
     VolumeDao volDao;
     @Inject
+    VMInstanceDao instanceDao;
+    @Inject
     VMTemplateDao templateDao;
     @Inject
     SnapshotManager snapshotMgr;
@@ -130,6 +145,11 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
         return true;
     }
 
+    @Override
+    public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+        return false;
+    }
+
     @DB
     protected Answer copyVolumeFromImage(DataObject srcData, DataObject destData) {
         String value = configDao.getValue(Config.RecreateSystemVmEnabled.key());
@@ -393,6 +413,53 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
         return cvAnswer;
     }
 
+    protected Answer migrateVolumeToPool(DataObject srcData, DataStore destStore) {
+        VolumeInfo volume = (VolumeInfo)srcData;
+        Long instanceId = volume.getInstanceId();
+        StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(destStore.getId(), DataStoreRole.Primary);
+        MigrateVolumeAnswer answer = null;
+        VMInstanceVO vmInstance = null;
+        if (instanceId != null) {
+            vmInstance = instanceDao.findById(instanceId);
+        }
+
+        Long hostId = null;
+        if (vmInstance != null) {
+            hostId = vmInstance.getHostId();
+        }
+
+        try {
+            if (hostId != null) {
+                MigrateVolumeCommand command = new MigrateVolumeCommand(volume.getId(), volume.getPath(), destPool);
+                answer = (MigrateVolumeAnswer) this.agentMgr.send(hostId, command);
+            }
+        } catch (OperationTimedoutException e) {
+            s_logger.error("Operation timed out on storage motion for volume " + volume, e);
+            throw new CloudRuntimeException("Failed to live migrate volume " + volume + " to storage pool " +
+                    destPool, e);
+        } catch (AgentUnavailableException e) {
+            s_logger.error("Agent unavailable exception while doing storage motion for volume " + volume, e);
+            throw new CloudRuntimeException("Failed to live migrate volume " + volume + " to storage pool " +
+                    destPool, e);
+        }
+
+        if (answer == null || !answer.getResult()) {
+            throw new CloudRuntimeException("Failed to migrate volume " + volume + " to storage pool " + destPool);
+        } else {
+            // Update the volume details after migration.
+            VolumeVO volumeVo = this.volDao.findById(volume.getId());
+            Long oldPoolId = volume.getPoolId();
+            volumeVo.setPath(answer.getVolumePath());
+            volumeVo.setFolder(destPool.getPath());
+            volumeVo.setPodId(destPool.getPodId());
+            volumeVo.setPoolId(destPool.getId());
+            volumeVo.setLastPoolId(oldPoolId);
+            this.volDao.update(volume.getId(), volumeVo);
+        }
+
+        return answer;
+    }
+
     @Override
     public Void copyAsync(DataObject srcData, DataObject destData,
             AsyncCompletionCallback<CopyCommandResult> callback) {
@@ -419,7 +486,12 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
             	answer = cloneVolume(srcData, destData);
             } else if (destData.getType() == DataObjectType.VOLUME
                     && srcData.getType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
-            	answer = copyVolumeBetweenPools(srcData, destData);
+                if (srcData.getId() == destData.getId()) {
+                    // The volume has to be migrated across storage pools.
+                    answer = migrateVolumeToPool(srcData, destData.getDataStore());
+                } else {
+                    answer = copyVolumeBetweenPools(srcData, destData);
+                }
             } else if (srcData.getType() == DataObjectType.SNAPSHOT &&
             		destData.getType() == DataObjectType.SNAPSHOT) {
             	answer = copySnapshot(srcData, destData);
@@ -435,6 +507,16 @@ public class AncientDataMotionStrategy implements DataMotionStrategy {
         return null;
     }
 
+    @Override
+    public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            AsyncCompletionCallback<CopyCommandResult> callback) {
+        CopyCommandResult result = new CopyCommandResult(null, null);
+        result.setResult("Unsupported operation requested for copying data.");
+        callback.complete(result);
+
+        return null;
+    }
+
     @DB
     protected Answer createTemplateFromSnashot(DataObject srcData,
             DataObject destData) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
index db36f64..5ecbcb3 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionService.java
@@ -18,11 +18,20 @@
  */
 package org.apache.cloudstack.storage.motion;
 
+import java.util.Map;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
 public interface DataMotionService {
     public void copyAsync(DataObject srcData, DataObject destData,
             AsyncCompletionCallback<CopyCommandResult> callback);
+    public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+            Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
index 343140f..b74e10c 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionServiceImpl.java
@@ -19,14 +19,19 @@
 package org.apache.cloudstack.storage.motion;
 
 import java.util.List;
+import java.util.Map;
 
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.springframework.stereotype.Component;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 @Component
@@ -58,4 +63,15 @@ public class DataMotionServiceImpl implements DataMotionService {
         throw new CloudRuntimeException("can't find strategy to move data");
     }
 
+    @Override
+    public void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+            Host srcHost, Host destHost, AsyncCompletionCallback<CopyCommandResult> callback) {
+        for (DataMotionStrategy strategy : strategies) {
+            if (strategy.canHandle(volumeMap, srcHost, destHost)) {
+                strategy.copyAsync(volumeMap, vmTo, srcHost, destHost, callback);
+                return;
+            }
+        }
+        throw new CloudRuntimeException("can't find strategy to move data");
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
index ba40c6d..e3859b4 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/motion/DataMotionStrategy.java
@@ -18,13 +18,23 @@
  */
 package org.apache.cloudstack.storage.motion;
 
+import java.util.Map;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.Host;
+
 public interface DataMotionStrategy {
     public boolean canHandle(DataObject srcData, DataObject destData);
+    public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost);
 
     public Void copyAsync(DataObject srcData, DataObject destData,
             AsyncCompletionCallback<CopyCommandResult> callback);
+    public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            AsyncCompletionCallback<CopyCommandResult> callback);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index ceadb25..ea31be3 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -176,6 +176,8 @@ public class VolumeObject implements VolumeInfo {
                     volEvent = Volume.Event.CreateRequested;
                 } else if (event == ObjectInDataStoreStateMachine.Event.CopyingRequested) {
                     volEvent = Volume.Event.CopyRequested;
+                } else if (event == ObjectInDataStoreStateMachine.Event.MigrationRequested) {
+                    volEvent = Volume.Event.MigrationRequested;
                 }
             }
             

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index 32e7d27..e3526de 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -18,6 +18,10 @@
  */
 package org.apache.cloudstack.storage.volume;
 
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity;
@@ -27,6 +31,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@@ -40,11 +45,14 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager;
 import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
 import org.apache.cloudstack.storage.datastore.PrimaryDataStore;
 import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.motion.DataMotionService;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.host.Host;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
@@ -561,7 +569,163 @@ public class VolumeServiceImpl implements VolumeService {
         
         return null;
     }
-    
+
+    private class MigrateVolumeContext<T> extends AsyncRpcConext<T> {
+        final VolumeInfo srcVolume;
+        final VolumeInfo destVolume;
+        final DataStore destStore;
+        final AsyncCallFuture<VolumeApiResult> future;
+        /**
+         * @param callback
+         */
+        public MigrateVolumeContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<VolumeApiResult> future,
+                VolumeInfo srcVolume, VolumeInfo destVolume, DataStore destStore) {
+            super(callback);
+            this.srcVolume = srcVolume;
+            this.destVolume = destVolume;
+            this.destStore = destStore;
+            this.future = future;
+        }
+    }
+
+    @Override
+    public AsyncCallFuture<VolumeApiResult> migrateVolume(VolumeInfo srcVolume, DataStore destStore) {
+        AsyncCallFuture<VolumeApiResult> future = new AsyncCallFuture<VolumeApiResult>();
+        VolumeApiResult res = new VolumeApiResult(srcVolume);
+        try {
+            if (!this.snapshotMgr.canOperateOnVolume(srcVolume)) {
+                s_logger.debug("Snapshots are being created on this volume. This volume cannot be migrated now.");
+                res.setResult("Snapshots are being created on this volume. This volume cannot be migrated now.");
+                future.complete(res);
+                return future;
+            }
+
+            VolumeInfo destVolume = this.volFactory.getVolume(srcVolume.getId(), destStore);
+            srcVolume.processEvent(Event.MigrationRequested);
+            MigrateVolumeContext<VolumeApiResult> context = new MigrateVolumeContext<VolumeApiResult>(null, future,
+                    srcVolume, destVolume, destStore);
+            AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+            caller.setCallback(caller.getTarget().migrateVolumeCallBack(null, null)).setContext(context);
+            this.motionSrv.copyAsync(srcVolume, destVolume, caller);
+        } catch (Exception e) {
+            s_logger.debug("Failed to copy volume", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+        return future;
+    }
+
+    protected Void migrateVolumeCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+            MigrateVolumeContext<VolumeApiResult> context) {
+        VolumeInfo srcVolume = context.srcVolume;
+        VolumeInfo destVolume = context.destVolume;
+        CopyCommandResult result = callback.getResult();
+        AsyncCallFuture<VolumeApiResult> future = context.future;
+        VolumeApiResult res = new VolumeApiResult(srcVolume);
+        try {
+            if (result.isFailed()) {
+                res.setResult(result.getResult());
+                srcVolume.processEvent(Event.OperationFailed);
+                future.complete(res);
+            } else {
+                srcVolume.processEvent(Event.OperationSuccessed);
+                future.complete(res);
+            }
+        } catch (Exception e) {
+            s_logger.error("Failed to process copy volume callback", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+
+        return null;
+    }
+
+    private class MigrateVmWithVolumesContext<T> extends AsyncRpcConext<T> {
+        final Map<VolumeInfo, DataStore> volumeToPool;
+        final AsyncCallFuture<CommandResult> future;
+        /**
+         * @param callback
+         */
+        public MigrateVmWithVolumesContext(AsyncCompletionCallback<T> callback, AsyncCallFuture<CommandResult> future,
+                Map<VolumeInfo, DataStore> volumeToPool) {
+            super(callback);
+            this.volumeToPool = volumeToPool;
+            this.future = future;
+        }
+    }
+
+    @Override
+    public AsyncCallFuture<CommandResult> migrateVolumes(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo,
+            Host srcHost, Host destHost) {
+        AsyncCallFuture<CommandResult> future = new AsyncCallFuture<CommandResult>();
+        CommandResult res = new CommandResult();
+        try {
+            // Check to make sure there are no snapshot operations on a volume and
+            // put it in the migrating state.
+            List<VolumeInfo> volumesMigrating = new ArrayList<VolumeInfo>();
+            for (Map.Entry<VolumeInfo, DataStore> entry : volumeMap.entrySet()) {
+                VolumeInfo volume = entry.getKey();
+                if (!this.snapshotMgr.canOperateOnVolume(volume)) {
+                    s_logger.debug("Snapshots are being created on a volume. Volumes cannot be migrated now.");
+                    res.setResult("Snapshots are being created on a volume. Volumes cannot be migrated now.");
+                    future.complete(res);
+
+                    // All the volumes that are already in migrating state need to be put back in ready state.
+                    for (VolumeInfo volumeMigrating : volumesMigrating) {
+                        volumeMigrating.processEvent(Event.OperationFailed);
+                    }
+                    return future;
+                } else {
+                    volume.processEvent(Event.MigrationRequested);
+                    volumesMigrating.add(volume);
+                }
+            }
+
+            MigrateVmWithVolumesContext<CommandResult> context = new MigrateVmWithVolumesContext<CommandResult>(null,
+                    future, volumeMap);
+            AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> caller = AsyncCallbackDispatcher.create(this);
+            caller.setCallback(caller.getTarget().migrateVmWithVolumesCallBack(null, null)).setContext(context);
+            this.motionSrv.copyAsync(volumeMap, vmTo, srcHost, destHost, caller);
+
+        } catch (Exception e) {
+            s_logger.debug("Failed to copy volume", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+
+        return future;
+    }
+
+    protected Void migrateVmWithVolumesCallBack(AsyncCallbackDispatcher<VolumeServiceImpl, CopyCommandResult> callback,
+            MigrateVmWithVolumesContext<CommandResult> context) {
+        Map<VolumeInfo, DataStore> volumeToPool = context.volumeToPool;
+        CopyCommandResult result = callback.getResult();
+        AsyncCallFuture<CommandResult> future = context.future;
+        CommandResult res = new CommandResult();
+        try {
+            if (result.isFailed()) {
+                res.setResult(result.getResult());
+                for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+                    VolumeInfo volume = entry.getKey();
+                    volume.processEvent(Event.OperationFailed);
+                }
+                future.complete(res);
+            } else {
+                for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+                    VolumeInfo volume = entry.getKey();
+                    volume.processEvent(Event.OperationSuccessed);
+                }
+                future.complete(res);
+            }
+        } catch (Exception e) {
+            s_logger.error("Failed to process copy volume callback", e);
+            res.setResult(e.toString());
+            future.complete(res);
+        }
+
+        return null;
+    }
+
     @Override
     public AsyncCallFuture<VolumeApiResult> registerVolume(VolumeInfo volume, DataStore store) {
         

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
----------------------------------------------------------------------
diff --git a/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java b/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
index a672efd..8243f3a 100755
--- a/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
+++ b/plugins/host-allocators/random/src/com/cloud/agent/manager/allocator/impl/RandomAllocator.java
@@ -55,6 +55,62 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
 
     @Override
     public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
+            ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+        long dcId = plan.getDataCenterId();
+        Long podId = plan.getPodId();
+        Long clusterId = plan.getClusterId();
+        ServiceOffering offering = vmProfile.getServiceOffering();
+        List<Host> suitableHosts = new ArrayList<Host>();
+
+        if (type == Host.Type.Storage) {
+            return suitableHosts;
+        }
+
+        String hostTag = offering.getHostTag();
+        if(hostTag != null){
+            s_logger.debug("Looking for hosts in dc: " + dcId + "  pod:" + podId + "  cluster:" + clusterId +
+                    " having host tag:" + hostTag);
+        }else{
+            s_logger.debug("Looking for hosts in dc: " + dcId + "  pod:" + podId + "  cluster:" + clusterId);
+        }
+
+        // list all computing hosts, regardless of whether they support routing...it's random after all
+        if(hostTag != null){
+            hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTag));
+        }else{
+            hosts.retainAll(_resourceMgr.listAllUpAndEnabledHosts(type, clusterId, podId, dcId));
+        }
+
+        s_logger.debug("Random Allocator found " + hosts.size() + "  hosts");
+        if (hosts.size() == 0) {
+            return suitableHosts;
+        }
+
+        Collections.shuffle(hosts);
+        for (Host host : hosts) {
+            if(suitableHosts.size() == returnUpTo){
+                break;
+            }
+
+            if (!avoid.shouldAvoid(host)) {
+                suitableHosts.add(host);
+            } else {
+                if (s_logger.isDebugEnabled()) {
+                    s_logger.debug("Host name: " + host.getName() + ", hostId: "+ host.getId() +" is in avoid set, " +
+                            "skipping this and trying other available hosts");
+                }
+            }
+        }
+
+        if (s_logger.isDebugEnabled()) {
+            s_logger.debug("Random Host Allocator returning "+suitableHosts.size() +" suitable hosts");
+        }
+
+        return suitableHosts;
+    }
+
+    @Override
+    public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
             ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
 
         long dcId = plan.getDataCenterId();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index 4ef583a..46ae35a 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -3358,7 +3358,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         vm.setMemoryLimits(conn, maxMemsize, maxMemsize, minMemsize, maxMemsize);
     }
 
-    private void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException {
+    protected void waitForTask(Connection c, Task task, long pollInterval, long timeout) throws XenAPIException, XmlRpcException {
         long beginTime = System.currentTimeMillis();
         while (task.getStatus(c) == Types.TaskStatusType.PENDING) {
             try {
@@ -3374,7 +3374,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    private void checkForSuccess(Connection c, Task task) throws XenAPIException, XmlRpcException {
+    protected void checkForSuccess(Connection c, Task task) throws XenAPIException, XmlRpcException {
         if (task.getStatus(c) == Types.TaskStatusType.SUCCESS) {
             return;
         } else {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
index d64e173..96a90a6 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
@@ -132,6 +132,7 @@ public class XenServer56FP1Resource extends XenServer56Resource {
         record.affinity = host;
         record.otherConfig.remove("disks");
         record.otherConfig.remove("default_template");
+        record.otherConfig.remove("mac_seed");
         record.isATemplate = false;
         record.nameLabel = vmSpec.getName();
         record.actionsAfterCrash = Types.OnCrashBehaviour.DESTROY;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
index 8d267b1..bb31136 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer610Resource.java
@@ -20,6 +20,9 @@ package com.cloud.hypervisor.xen.resource;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 import javax.ejb.Local;
 
@@ -28,7 +31,34 @@ import org.apache.log4j.Logger;
 import com.cloud.resource.ServerResource;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.script.Script;
-
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.storage.MigrateVolumeAnswer;
+import com.cloud.agent.api.storage.MigrateVolumeCommand;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageReceiveAnswer;
+import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.NicTO;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.Network;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Task;
+import com.xensource.xenapi.Types;
+import com.xensource.xenapi.VBD;
+import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VIF;
+import com.xensource.xenapi.VM;
 
 @Local(value=ServerResource.class)
 public class XenServer610Resource extends XenServer56FP1Resource {
@@ -55,4 +85,331 @@ public class XenServer610Resource extends XenServer56FP1Resource {
         files.add(file);
         return files;
     }
+
+    @Override
+    public Answer executeRequest(Command cmd) {
+        if (cmd instanceof MigrateWithStorageCommand) {
+            return execute((MigrateWithStorageCommand) cmd);
+        } else if (cmd instanceof MigrateWithStorageReceiveCommand) {
+            return execute((MigrateWithStorageReceiveCommand) cmd);
+        } else if (cmd instanceof MigrateWithStorageSendCommand) {
+            return execute((MigrateWithStorageSendCommand) cmd);
+        } else if (cmd instanceof MigrateWithStorageCompleteCommand) {
+            return execute((MigrateWithStorageCompleteCommand) cmd);
+        } else if (cmd instanceof MigrateVolumeCommand) {
+            return execute((MigrateVolumeCommand) cmd);
+        } else {
+            return super.executeRequest(cmd);
+        }
+    }
+
+    private List<VolumeTO> getUpdatedVolumePathsOfMigratedVm(Connection connection, VM migratedVm,
+            VolumeTO[] volumes) throws CloudRuntimeException {
+        List<VolumeTO> volumeToList = new ArrayList<VolumeTO>();
+
+        try {
+            // Volume paths would have changed. Return that information.
+            Set<VBD> vbds = migratedVm.getVBDs(connection);
+            Map<String, VDI> deviceIdToVdiMap = new HashMap<String, VDI>();
+            // get vdi:vbdr to a map
+            for (VBD vbd : vbds) {
+                VBD.Record vbdr = vbd.getRecord(connection);
+                if (vbdr.type == Types.VbdType.DISK) {
+                    VDI vdi = vbdr.VDI;
+                    deviceIdToVdiMap.put(vbdr.userdevice, vdi);
+                }
+            }
+
+            for (VolumeTO volumeTo : volumes) {
+                Long deviceId = volumeTo.getDeviceId();
+                VDI vdi = deviceIdToVdiMap.get(deviceId.toString());
+                volumeTo.setPath(vdi.getUuid(connection));
+                volumeToList.add(volumeTo);
+            }
+        } catch (Exception e) {
+            s_logger.error("Unable to get the updated VDI paths of the migrated vm " + e.toString(), e);
+            throw new CloudRuntimeException("Unable to get the updated VDI paths of the migrated vm " + e.toString(), e);
+        }
+
+        return volumeToList;
+    }
+
+    protected MigrateWithStorageAnswer execute(MigrateWithStorageCommand cmd) {
+        Connection connection = getConnection();
+        VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+        Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
+        final String vmName = vmSpec.getName();
+        State state = s_vms.getState(_cluster, vmName);
+        Task task = null;
+
+        synchronized (_cluster.intern()) {
+            s_vms.put(_cluster, _name, vmName, State.Stopping);
+        }
+
+        try {
+            prepareISO(connection, vmSpec.getName());
+            Map<String, String> other = new HashMap<String, String>();
+            other.put("live", "true");
+            Network networkForSm = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
+            Host host = Host.getByUuid(connection, _host.uuid);
+            Map<String,String> token = host.migrateReceive(connection, networkForSm, other);
+
+            // Get the vm to migrate.
+            Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+            VM vmToMigrate = vms.iterator().next();
+
+            // Create the vif map. The vm stays in the same cluster so we have to pass an empty vif map.
+            Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+            Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+            for (Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
+                vdiMap.put(getVDIbyUuid(connection, entry.getKey().getPath()),
+                        getStorageRepository(connection, entry.getValue().getUuid()));
+            }
+
+            // Check migration with storage is possible.
+            task = vmToMigrate.assertCanMigrateAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds
+                long timeout = (_migratewait) * 1000L;
+                waitForTask(connection, task, 1000, timeout);
+                checkForSuccess(connection, task);
+            } catch (Types.HandleInvalid e) {
+                s_logger.error("Error while checking if vm " + vmName + " can be migrated to the destination host " +
+                        host, e);
+                throw new CloudRuntimeException("Error while checking if vm " + vmName + " can be migrated to the " +
+                        "destination host " + host, e);
+            }
+
+            // Migrate now.
+            task = vmToMigrate.migrateSendAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds.
+                long timeout = (_migratewait) * 1000L;
+                waitForTask(connection, task, 1000, timeout);
+                checkForSuccess(connection, task);
+            } catch (Types.HandleInvalid e) {
+                s_logger.error("Error while migrating vm " + vmName + " to the destination host " + host, e);
+                throw new CloudRuntimeException("Error while migrating vm " + vmName + " to the destination host " +
+                        host, e);
+            }
+
+            // Volume paths would have changed. Return that information.
+            List<VolumeTO> volumeToList = getUpdatedVolumePathsOfMigratedVm(connection, vmToMigrate, vmSpec.getDisks());
+            vmToMigrate.setAffinity(connection, host);
+            state = State.Stopping;
+
+            return new MigrateWithStorageAnswer(cmd, volumeToList);
+        } catch (Exception e) {
+            s_logger.warn("Catch Exception " + e.getClass().getName() + ". Storage motion failed due to " +
+                    e.toString(), e);
+            return new MigrateWithStorageAnswer(cmd, e);
+        } finally {
+            if (task != null) {
+                try {
+                    task.destroy(connection);
+                } catch (Exception e) {
+                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.uuid +" due to " +
+                            e.toString());
+                }
+            }
+
+            synchronized (_cluster.intern()) {
+                s_vms.put(_cluster, _name, vmName, state);
+            }
+        }
+    }
+
+    protected MigrateWithStorageReceiveAnswer execute(MigrateWithStorageReceiveCommand cmd) {
+        Connection connection = getConnection();
+        VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+        Map<VolumeTO, StorageFilerTO> volumeToFiler = cmd.getVolumeToFiler();
+
+        try {
+            // Get a map of all the SRs to which the vdis will be migrated.
+            Map<VolumeTO, Object> volumeToSr = new HashMap<VolumeTO, Object>();
+            for (Map.Entry<VolumeTO, StorageFilerTO> entry : volumeToFiler.entrySet()) {
+                SR sr = getStorageRepository(connection, entry.getValue().getUuid());
+                volumeToSr.put(entry.getKey(), sr);
+            }
+
+            // Get the list of networks to which the vifs will attach.
+            Map<NicTO, Object> nicToNetwork = new HashMap<NicTO, Object>();
+            for (NicTO nicTo : vmSpec.getNics()) {
+                Network network = getNetwork(connection, nicTo);
+                nicToNetwork.put(nicTo, network);
+            }
+
+            Map<String, String> other = new HashMap<String, String>();
+            other.put("live", "true");
+            Network network = getNativeNetworkForTraffic(connection, TrafficType.Storage, null).getNetwork();
+            Host host = Host.getByUuid(connection, _host.uuid);
+            Map<String,String> token = host.migrateReceive(connection, network, other);
+
+            return new MigrateWithStorageReceiveAnswer(cmd, volumeToSr, nicToNetwork, token);
+        } catch (CloudRuntimeException e) {
+            s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageReceiveAnswer(cmd, e);
+        } catch (Exception e) {
+            s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageReceiveAnswer(cmd, e);
+        }
+    }
+
+    protected MigrateWithStorageSendAnswer execute(MigrateWithStorageSendCommand cmd) {
+        Connection connection = getConnection();
+        VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+        Map<VolumeTO, Object> volumeToSr = cmd.getVolumeToSr();
+        Map<NicTO, Object> nicToNetwork = cmd.getNicToNetwork();
+        Map<String, String> token = cmd.getToken();
+        final String vmName = vmSpec.getName();
+        State state = s_vms.getState(_cluster, vmName);
+        Set<VolumeTO> volumeToSet = null;
+        boolean migrated = false;
+        Task task = null;
+
+        synchronized (_cluster.intern()) {
+            s_vms.put(_cluster, _name, vmName, State.Stopping);
+        }
+
+        try {
+            Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+            VM vmToMigrate = vms.iterator().next();
+            Map<String, String> other = new HashMap<String, String>();
+            other.put("live", "true");
+
+            // Create the vdi map which tells what volumes of the vm need to go on which sr on the destination.
+            Map<VDI, SR> vdiMap = new HashMap<VDI, SR>();
+            for (Map.Entry<VolumeTO, Object> entry : volumeToSr.entrySet()) {
+                if  (entry.getValue() instanceof SR) {
+                    SR sr = (SR)entry.getValue();
+                    VDI vdi = getVDIbyUuid(connection, entry.getKey().getPath());
+                    vdiMap.put(vdi, sr);
+                } else {
+                    throw new CloudRuntimeException("The object " + entry.getValue() + " passed is not of type SR.");
+                }
+            }
+
+            // Create the vif map.
+            Map<VIF, Network> vifMap = new HashMap<VIF, Network>();
+            for (Map.Entry<NicTO, Object> entry : nicToNetwork.entrySet()) {
+                if (entry.getValue() instanceof Network) {
+                    Network network = (Network)entry.getValue();
+                    VIF vif = getVifByMac(connection, vmToMigrate, entry.getKey().getMac());
+                    vifMap.put(vif, network);
+                } else {
+                    throw new CloudRuntimeException("The object " + entry.getValue() + " passed is not of type Network.");
+                }
+            }
+
+            // Check migration with storage is possible.
+            task = vmToMigrate.assertCanMigrateAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds.
+                long timeout = (_migratewait) * 1000L;
+                waitForTask(connection, task, 1000, timeout);
+                checkForSuccess(connection, task);
+            } catch (Types.HandleInvalid e) {
+                s_logger.error("Error while checking if vm " + vmName + " can be migrated.", e);
+                throw new CloudRuntimeException("Error while checking if vm " + vmName + " can be migrated.", e);
+            }
+
+            // Migrate now.
+            task = vmToMigrate.migrateSendAsync(connection, token, true, vdiMap, vifMap, other);
+            try {
+                // poll every 1 seconds.
+                long timeout = (_migratewait) * 1000L;
+                waitForTask(connection, task, 1000, timeout);
+                checkForSuccess(connection, task);
+            } catch (Types.HandleInvalid e) {
+                s_logger.error("Error while migrating vm " + vmName, e);
+                throw new CloudRuntimeException("Error while migrating vm " + vmName, e);
+            }
+
+            migrated = true;
+            return new MigrateWithStorageSendAnswer(cmd, volumeToSet);
+        } catch (CloudRuntimeException e) {
+            s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageSendAnswer(cmd, e);
+        } catch (Exception e) {
+            s_logger.error("Migration of vm " + vmName + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageSendAnswer(cmd, e);
+        } finally {
+            if (task != null) {
+                try {
+                    task.destroy(connection);
+                } catch (Exception e) {
+                    s_logger.debug("Unable to destroy task " + task.toString() + " on host " + _host.uuid +" due to " +
+                            e.toString());
+                }
+            }
+
+            // Keep cluster/vm sync happy.
+            synchronized (_cluster.intern()) {
+                if (migrated) {
+                    s_vms.remove(_cluster, _name, vmName);
+                } else {
+                    s_vms.put(_cluster, _name, vmName, state);
+                }
+            }
+        }
+    }
+
+    protected MigrateWithStorageCompleteAnswer execute(MigrateWithStorageCompleteCommand cmd) {
+        Connection connection = getConnection();
+        VirtualMachineTO vmSpec = cmd.getVirtualMachine();
+
+        try {
+            Host host = Host.getByUuid(connection, _host.uuid);
+            Set<VM> vms = VM.getByNameLabel(connection, vmSpec.getName());
+            VM migratedVm = vms.iterator().next();
+
+            // Check the vm is present on the new host.
+            if (migratedVm == null) {
+                throw new CloudRuntimeException("Couldn't find the migrated vm " + vmSpec.getName() +
+                        " on the destination host.");
+            }
+
+            // Volume paths would have changed. Return that information.
+            List<VolumeTO > volumeToSet = getUpdatedVolumePathsOfMigratedVm(connection, migratedVm, vmSpec.getDisks());
+            migratedVm.setAffinity(connection, host);
+
+            synchronized (_cluster.intern()) {
+                s_vms.put(_cluster, _name, vmSpec.getName(), State.Running);
+            }
+
+            return new MigrateWithStorageCompleteAnswer(cmd, volumeToSet);
+        } catch (CloudRuntimeException e) {
+            s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageCompleteAnswer(cmd, e);
+        } catch (Exception e) {
+            s_logger.error("Migration of vm " + vmSpec.getName() + " with storage failed due to " + e.toString(), e);
+            return new MigrateWithStorageCompleteAnswer(cmd, e);
+        }
+    }
+
+    protected MigrateVolumeAnswer execute(MigrateVolumeCommand cmd) {
+        Connection connection = getConnection();
+        String volumeUUID = cmd.getVolumePath();
+        StorageFilerTO poolTO = cmd.getPool();
+
+        try {
+            SR destinationPool = getStorageRepository(connection, poolTO.getUuid());
+            VDI srcVolume = getVDIbyUuid(connection, volumeUUID);
+            Map<String, String> other = new HashMap<String, String>();
+            other.put("live", "true");
+
+            // Live migrate the vdi across pool.
+            Task task = srcVolume.poolMigrateAsync(connection, destinationPool, other);
+            long timeout = (_migratewait) * 1000L;
+            waitForTask(connection, task, 1000, timeout);
+            checkForSuccess(connection, task);
+            VDI dvdi = Types.toVDI(task, connection);
+
+            return new MigrateVolumeAnswer(cmd, true, null, dvdi.getUuid(connection));
+        } catch (Exception e) {
+            String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
+            s_logger.error(msg, e);
+            return new MigrateVolumeAnswer(cmd, false, msg, null);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
new file mode 100644
index 0000000..353f2b5
--- /dev/null
+++ b/plugins/hypervisors/xen/src/org/apache/cloudstack/storage/motion/XenServerStorageMotionStrategy.java
@@ -0,0 +1,239 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cloudstack.storage.motion;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.MigrateWithStorageReceiveAnswer;
+import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.Host;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Component
+public class XenServerStorageMotionStrategy implements DataMotionStrategy {
+    private static final Logger s_logger = Logger.getLogger(XenServerStorageMotionStrategy.class);
+    @Inject AgentManager agentMgr;
+    @Inject VolumeDao volDao;
+    @Inject VolumeDataFactory volFactory;
+    @Inject PrimaryDataStoreDao storagePoolDao;
+    @Inject VMInstanceDao instanceDao;
+
+    @Override
+    public boolean canHandle(DataObject srcData, DataObject destData) {
+        return false;
+    }
+
+    @Override
+    public boolean canHandle(Map<VolumeInfo, DataStore> volumeMap, Host srcHost, Host destHost) {
+        return true;
+    }
+
+    @Override
+    public Void copyAsync(DataObject srcData, DataObject destData,
+            AsyncCompletionCallback<CopyCommandResult> callback) {
+        CopyCommandResult result = new CopyCommandResult(null, null);
+        result.setResult("Unsupported operation requested for copying data.");
+        callback.complete(result);
+
+        return null;
+    }
+
+    @Override
+    public Void copyAsync(Map<VolumeInfo, DataStore> volumeMap, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            AsyncCompletionCallback<CopyCommandResult> callback) {
+        Answer answer = null;
+        String errMsg = null;
+        try {
+            VMInstanceVO instance = instanceDao.findById(vmTo.getId());
+            if (instance != null) {
+                if (srcHost.getClusterId() == destHost.getClusterId()) {
+                    answer = migrateVmWithVolumesWithinCluster(instance, vmTo, srcHost, destHost, volumeMap);
+                } else {
+                    answer = migrateVmWithVolumesAcrossCluster(instance, vmTo, srcHost, destHost, volumeMap);
+                }
+            } else {
+                throw new CloudRuntimeException("Unsupported operation requested for moving data.");
+            }
+        } catch (Exception e) {
+            s_logger.error("copy failed", e);
+            errMsg = e.toString();
+        }
+
+        CopyCommandResult result = new CopyCommandResult(null, answer);
+        result.setResult(errMsg);
+        callback.complete(result);
+        return null;
+    }
+
+    private Answer migrateVmWithVolumesAcrossCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost,
+            Host destHost, Map<VolumeInfo, DataStore> volumeToPool) throws AgentUnavailableException {
+
+        // Initiate migration of a virtual machine with it's volumes.
+        try {
+            Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
+            for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+                VolumeInfo volume = entry.getKey();
+                VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
+                StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
+                volumeToFilerto.put(volumeTo, filerTo);
+            }
+
+            // Migration across cluster needs to be done in three phases.
+            // 1. Send a migrate receive command to the destination host so that it is ready to receive a vm.
+            // 2. Send a migrate send command to the source host. This actually migrates the vm to the destination.
+            // 3. Complete the process. Update the volume details.
+            MigrateWithStorageReceiveCommand receiveCmd = new MigrateWithStorageReceiveCommand(to, volumeToFilerto);
+            MigrateWithStorageReceiveAnswer receiveAnswer = (MigrateWithStorageReceiveAnswer) agentMgr.send(
+                    destHost.getId(), receiveCmd);
+            if (receiveAnswer == null) {
+                s_logger.error("Migration with storage of vm " + vm+ " to host " + destHost + " failed.");
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+            } else if (!receiveAnswer.getResult()) {
+                s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + receiveAnswer.getDetails());
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+                        ". " + receiveAnswer.getDetails());
+            }
+
+            MigrateWithStorageSendCommand sendCmd = new MigrateWithStorageSendCommand(to, receiveAnswer.getVolumeToSr(),
+                    receiveAnswer.getNicToNetwork(), receiveAnswer.getToken());
+            MigrateWithStorageSendAnswer sendAnswer = (MigrateWithStorageSendAnswer) agentMgr.send(
+                    srcHost.getId(), sendCmd);
+            if (sendAnswer == null) {
+                s_logger.error("Migration with storage of vm " + vm+ " to host " + destHost + " failed.");
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+            } else if (!sendAnswer.getResult()) {
+                s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + sendAnswer.getDetails());
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+                        ". " + sendAnswer.getDetails());
+            }
+
+            MigrateWithStorageCompleteCommand command = new MigrateWithStorageCompleteCommand(to);
+            MigrateWithStorageCompleteAnswer answer = (MigrateWithStorageCompleteAnswer) agentMgr.send(
+                    destHost.getId(), command);
+            if (answer == null) {
+                s_logger.error("Migration with storage of vm " + vm + " failed.");
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+            } else if (!answer.getResult()) {
+                s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + answer.getDetails());
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+                        ". " + answer.getDetails());
+            } else {
+                // Update the volume details after migration.
+                updateVolumePathsAfterMigration(volumeToPool, answer.getVolumeTos());
+            }
+
+            return answer;
+        } catch (OperationTimedoutException e) {
+            s_logger.error("Error while migrating vm " + vm + " to host " + destHost, e);
+            throw new AgentUnavailableException("Operation timed out on storage motion for " + vm, destHost.getId());
+        }
+    }
+
+    private Answer migrateVmWithVolumesWithinCluster(VMInstanceVO vm, VirtualMachineTO to, Host srcHost,
+            Host destHost, Map<VolumeInfo, DataStore> volumeToPool) throws AgentUnavailableException {
+
+        // Initiate migration of a virtual machine with it's volumes.
+        try {
+            Map<VolumeTO, StorageFilerTO> volumeToFilerto = new HashMap<VolumeTO, StorageFilerTO>();
+            for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+                VolumeInfo volume = entry.getKey();
+                VolumeTO volumeTo = new VolumeTO(volume, storagePoolDao.findById(volume.getPoolId()));
+                StorageFilerTO filerTo = new StorageFilerTO((StoragePool)entry.getValue());
+                volumeToFilerto.put(volumeTo, filerTo);
+            }
+
+            MigrateWithStorageCommand command = new MigrateWithStorageCommand(to, volumeToFilerto);
+            MigrateWithStorageAnswer answer = (MigrateWithStorageAnswer) agentMgr.send(destHost.getId(), command);
+            if (answer == null) {
+                s_logger.error("Migration with storage of vm " + vm + " failed.");
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost);
+            } else if (!answer.getResult()) {
+                s_logger.error("Migration with storage of vm " + vm+ " failed. Details: " + answer.getDetails());
+                throw new CloudRuntimeException("Error while migrating the vm " + vm + " to host " + destHost +
+                        ". " + answer.getDetails());
+            } else {
+                // Update the volume details after migration.
+                updateVolumePathsAfterMigration(volumeToPool, answer.getVolumeTos());
+            }
+
+            return answer;
+        } catch (OperationTimedoutException e) {
+            s_logger.error("Error while migrating vm " + vm + " to host " + destHost, e);
+            throw new AgentUnavailableException("Operation timed out on storage motion for " + vm, destHost.getId());
+        }
+    }
+
+    private void updateVolumePathsAfterMigration(Map<VolumeInfo, DataStore> volumeToPool, List<VolumeTO> volumeTos) {
+        for (Map.Entry<VolumeInfo, DataStore> entry : volumeToPool.entrySet()) {
+            boolean updated = false;
+            VolumeInfo volume = entry.getKey();
+            StoragePool pool = (StoragePool)entry.getValue();
+            for (VolumeTO volumeTo : volumeTos) {
+                if (volume.getId() == volumeTo.getId()) {
+                    VolumeVO volumeVO = volDao.findById(volume.getId());
+                    Long oldPoolId = volumeVO.getPoolId();
+                    volumeVO.setPath(volumeTo.getPath());
+                    volumeVO.setFolder(pool.getPath());
+                    volumeVO.setPodId(pool.getPodId());
+                    volumeVO.setPoolId(pool.getId());
+                    volumeVO.setLastPoolId(oldPoolId);
+                    volDao.update(volume.getId(), volumeVO);
+                    updated = true;
+                    break;
+                }
+            }
+
+            if (!updated) {
+                s_logger.error("Volume path wasn't updated for volume " + volume + " after it was migrated.");
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
index 60027e7..6700f22 100755
--- a/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/HostAllocator.java
@@ -21,6 +21,7 @@ import java.util.List;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.host.Host;
+import com.cloud.host.HostVO;
 import com.cloud.host.Host.Type;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.utils.component.Adapter;
@@ -63,8 +64,22 @@ public interface HostAllocator extends Adapter {
     **/ 
     
     public List<Host> allocateTo(VirtualMachineProfile<?extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity);
-	
-	
-	public static int RETURN_UPTO_ALL = -1;
-		
+
+    /**
+     * Determines which physical hosts are suitable to
+     * allocate the guest virtual machines on
+     *
+     * @param VirtualMachineProfile vmProfile
+     * @param DeploymentPlan plan
+     * @param GuestType type
+     * @param ExcludeList avoid
+     * @param List<HostVO> hosts
+     * @param int returnUpTo (use -1 to return all possible hosts)
+     * @param boolean considerReservedCapacity (default should be true, set to false if host capacity calculation should not look at reserved capacity)
+     * @return List<Host> List of hosts that are suitable for VM allocation
+     **/
+     public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity);
+
+     public static int RETURN_UPTO_ALL = -1;
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
index 0091e43..b54b1c1 100755
--- a/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/impl/FirstFitAllocator.java
@@ -172,6 +172,53 @@ public class FirstFitAllocator extends AdapterBase implements HostAllocator {
         return allocateTo(plan, offering, template, avoid, clusterHosts, returnUpTo, considerReservedCapacity, account);
     }
 
+    @Override
+    public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan,
+            Type type, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+        long dcId = plan.getDataCenterId();
+        Long podId = plan.getPodId();
+        Long clusterId = plan.getClusterId();
+        ServiceOffering offering = vmProfile.getServiceOffering();
+        VMTemplateVO template = (VMTemplateVO)vmProfile.getTemplate();
+        Account account = vmProfile.getOwner();
+        List<Host> suitableHosts = new ArrayList<Host>();
+
+        if (type == Host.Type.Storage) {
+            // FirstFitAllocator should be used for user VMs only since it won't care whether the host is capable of
+            // routing or not.
+            return suitableHosts;
+        }
+
+        String hostTagOnOffering = offering.getHostTag();
+        String hostTagOnTemplate = template.getTemplateTag();
+        boolean hasSvcOfferingTag = hostTagOnOffering != null ? true : false;
+        boolean hasTemplateTag = hostTagOnTemplate != null ? true : false;
+
+        String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
+        if (haVmTag != null) {
+            hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, haVmTag));
+        } else {
+            if (hostTagOnOffering == null && hostTagOnTemplate == null){
+                hosts.retainAll(_resourceMgr.listAllUpAndEnabledNonHAHosts(type, clusterId, podId, dcId));
+            } else {
+                if (hasSvcOfferingTag) {
+                    hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnOffering));
+                }
+
+                if (hasTemplateTag) {
+                    hosts.retainAll(_hostDao.listByHostTag(type, clusterId, podId, dcId, hostTagOnTemplate));
+                }
+            }
+        }
+
+        if (!hosts.isEmpty()) {
+            suitableHosts = allocateTo(plan, offering, template, avoid, hosts, returnUpTo, considerReservedCapacity,
+                    account);
+        }
+
+        return suitableHosts;
+    }
+
     protected List<Host> allocateTo(DeploymentPlan plan, ServiceOffering offering, VMTemplateVO template, ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity, Account account) {
         if (_allocationAlgorithm.equals("random") || _allocationAlgorithm.equals("userconcentratedpod_random")) {
         	// Shuffle this so that we don't check the hosts in the same order.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
index 90bd956..890c047 100755
--- a/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
+++ b/server/src/com/cloud/agent/manager/allocator/impl/TestingAllocator.java
@@ -29,6 +29,7 @@ import com.cloud.agent.manager.allocator.HostAllocator;
 import com.cloud.deploy.DeploymentPlan;
 import com.cloud.deploy.DeploymentPlanner.ExcludeList;
 import com.cloud.host.Host;
+import com.cloud.host.HostVO;
 import com.cloud.host.Host.Type;
 import com.cloud.host.dao.HostDao;
 import com.cloud.offering.ServiceOffering;
@@ -52,6 +53,12 @@ public class TestingAllocator extends AdapterBase implements HostAllocator {
 
     @Override
     public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
+            ExcludeList avoid, List<HostVO> hosts, int returnUpTo, boolean considerReservedCapacity) {
+        return allocateTo(vmProfile, plan, type, avoid, returnUpTo, considerReservedCapacity);
+    }
+
+    @Override
+    public List<Host> allocateTo(VirtualMachineProfile<? extends VirtualMachine> vmProfile, DeploymentPlan plan, Type type,
             ExcludeList avoid, int returnUpTo, boolean considerReservedCapacity) {
         List<Host> availableHosts = new ArrayList<Host>();
         Host host = null;    	

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/ApiDBUtils.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java
index 303f328..c60af27 100755
--- a/server/src/com/cloud/api/ApiDBUtils.java
+++ b/server/src/com/cloud/api/ApiDBUtils.java
@@ -36,6 +36,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse;
 import org.apache.cloudstack.api.response.DomainRouterResponse;
 import org.apache.cloudstack.api.response.EventResponse;
 import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.cloudstack.api.response.InstanceGroupResponse;
 import org.apache.cloudstack.api.response.ProjectAccountResponse;
 import org.apache.cloudstack.api.response.ProjectInvitationResponse;
@@ -43,6 +44,7 @@ import org.apache.cloudstack.api.response.ProjectResponse;
 import org.apache.cloudstack.api.response.ResourceTagResponse;
 import org.apache.cloudstack.api.response.SecurityGroupResponse;
 import org.apache.cloudstack.api.response.ServiceOfferingResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
@@ -1518,6 +1520,14 @@ public class ApiDBUtils {
         return _hostJoinDao.setHostResponse(vrData, vr);
     }
 
+    public static HostForMigrationResponse newHostForMigrationResponse(HostJoinVO vr, EnumSet<HostDetails> details) {
+        return _hostJoinDao.newHostForMigrationResponse(vr, details);
+    }
+
+    public static HostForMigrationResponse fillHostForMigrationDetails(HostForMigrationResponse vrData, HostJoinVO vr) {
+        return _hostJoinDao.setHostForMigrationResponse(vrData, vr);
+    }
+
     public static List<HostJoinVO> newHostView(Host vr){
         return _hostJoinDao.newHostView(vr);
     }
@@ -1543,6 +1553,15 @@ public class ApiDBUtils {
         return _poolJoinDao.setStoragePoolResponse(vrData, vr);
     }
 
+    public static StoragePoolForMigrationResponse newStoragePoolForMigrationResponse(StoragePoolJoinVO vr) {
+        return _poolJoinDao.newStoragePoolForMigrationResponse(vr);
+    }
+
+    public static StoragePoolForMigrationResponse fillStoragePoolForMigrationDetails(StoragePoolForMigrationResponse
+            vrData, StoragePoolJoinVO vr){
+        return _poolJoinDao.setStoragePoolForMigrationResponse(vrData, vr);
+    }
+
     public static List<StoragePoolJoinVO> newStoragePoolView(StoragePool vr){
         return _poolJoinDao.newStoragePoolView(vr);
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 7629e5e..a7d6165 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -65,6 +65,7 @@ import org.apache.cloudstack.api.response.FirewallRuleResponse;
 import org.apache.cloudstack.api.response.GlobalLoadBalancerResponse;
 import org.apache.cloudstack.api.response.GuestOSResponse;
 import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.cloudstack.api.response.HypervisorCapabilitiesResponse;
 import org.apache.cloudstack.api.response.IPAddressResponse;
 import org.apache.cloudstack.api.response.InstanceGroupResponse;
@@ -105,6 +106,7 @@ import org.apache.cloudstack.api.response.SnapshotResponse;
 import org.apache.cloudstack.api.response.SnapshotScheduleResponse;
 import org.apache.cloudstack.api.response.StaticRouteResponse;
 import org.apache.cloudstack.api.response.StorageNetworkIpRangeResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.cloudstack.api.response.SwiftResponse;
 import org.apache.cloudstack.api.response.SystemVmInstanceResponse;
@@ -511,6 +513,20 @@ public class ApiResponseHelper implements ResponseGenerator {
     }
 
     @Override
+    public HostForMigrationResponse createHostForMigrationResponse(Host host) {
+        return createHostForMigrationResponse(host, EnumSet.of(HostDetails.all));
+    }
+
+    @Override
+    public HostForMigrationResponse createHostForMigrationResponse(Host host, EnumSet<HostDetails> details) {
+        List<HostJoinVO> viewHosts = ApiDBUtils.newHostView(host);
+        List<HostForMigrationResponse> listHosts = ViewResponseHelper.createHostForMigrationResponse(details,
+                viewHosts.toArray(new HostJoinVO[viewHosts.size()]));
+        assert listHosts != null && listHosts.size() == 1 : "There should be one host returned";
+        return listHosts.get(0);
+    }
+
+    @Override
     public SwiftResponse createSwiftResponse(Swift swift) {
         SwiftResponse swiftResponse = new SwiftResponse();
         swiftResponse.setId(swift.getUuid());
@@ -908,16 +924,21 @@ public class ApiResponseHelper implements ResponseGenerator {
 
     }
 
-
-
     @Override
     public StoragePoolResponse createStoragePoolResponse(StoragePool pool) {
         List<StoragePoolJoinVO> viewPools = ApiDBUtils.newStoragePoolView(pool);
         List<StoragePoolResponse> listPools = ViewResponseHelper.createStoragePoolResponse(viewPools.toArray(new StoragePoolJoinVO[viewPools.size()]));
         assert listPools != null && listPools.size() == 1 : "There should be one storage pool returned";
         return listPools.get(0);
+    }
 
-
+    @Override
+    public StoragePoolForMigrationResponse createStoragePoolForMigrationResponse(StoragePool pool) {
+        List<StoragePoolJoinVO> viewPools = ApiDBUtils.newStoragePoolView(pool);
+        List<StoragePoolForMigrationResponse> listPools = ViewResponseHelper.createStoragePoolForMigrationResponse(
+                viewPools.toArray(new StoragePoolJoinVO[viewPools.size()]));
+        assert listPools != null && listPools.size() == 1 : "There should be one storage pool returned";
+        return listPools.get(0);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/ViewResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/ViewResponseHelper.java b/server/src/com/cloud/api/query/ViewResponseHelper.java
index dc2727e..827ae7b 100644
--- a/server/src/com/cloud/api/query/ViewResponseHelper.java
+++ b/server/src/com/cloud/api/query/ViewResponseHelper.java
@@ -30,6 +30,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse;
 import org.apache.cloudstack.api.response.DomainRouterResponse;
 import org.apache.cloudstack.api.response.EventResponse;
 import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.cloudstack.api.response.InstanceGroupResponse;
 import org.apache.cloudstack.api.response.ProjectAccountResponse;
 import org.apache.cloudstack.api.response.ProjectInvitationResponse;
@@ -38,6 +39,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
 import org.apache.cloudstack.api.response.SecurityGroupResponse;
 import org.apache.cloudstack.api.response.ServiceOfferingResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
@@ -230,6 +232,24 @@ public class ViewResponseHelper {
         return new ArrayList<HostResponse>(vrDataList.values());
     }
 
+    public static List<HostForMigrationResponse> createHostForMigrationResponse(EnumSet<HostDetails> details,
+            HostJoinVO... hosts) {
+        Hashtable<Long, HostForMigrationResponse> vrDataList = new Hashtable<Long, HostForMigrationResponse>();
+        // Initialise the vrdatalist with the input data
+        for (HostJoinVO vr : hosts) {
+            HostForMigrationResponse vrData = vrDataList.get(vr.getId());
+            if ( vrData == null ) {
+                // first time encountering this vm
+                vrData = ApiDBUtils.newHostForMigrationResponse(vr, details);
+            } else {
+                // update tags
+                vrData = ApiDBUtils.fillHostForMigrationDetails(vrData, vr);
+            }
+            vrDataList.put(vr.getId(), vrData);
+        }
+        return new ArrayList<HostForMigrationResponse>(vrDataList.values());
+    }
+
     public static List<VolumeResponse> createVolumeResponse(VolumeJoinVO... volumes) {
         Hashtable<Long, VolumeResponse> vrDataList = new Hashtable<Long, VolumeResponse>();
         for (VolumeJoinVO vr : volumes) {
@@ -265,6 +285,23 @@ public class ViewResponseHelper {
         return new ArrayList<StoragePoolResponse>(vrDataList.values());
     }
 
+    public static List<StoragePoolForMigrationResponse> createStoragePoolForMigrationResponse(StoragePoolJoinVO... pools) {
+        Hashtable<Long, StoragePoolForMigrationResponse> vrDataList = new Hashtable<Long, StoragePoolForMigrationResponse>();
+        // Initialise the vrdatalist with the input data
+        for (StoragePoolJoinVO vr : pools) {
+            StoragePoolForMigrationResponse vrData = vrDataList.get(vr.getId());
+            if ( vrData == null ) {
+                // first time encountering this vm
+                vrData = ApiDBUtils.newStoragePoolForMigrationResponse(vr);
+            } else {
+                // update tags
+                vrData = ApiDBUtils.fillStoragePoolForMigrationDetails(vrData, vr);
+            }
+            vrDataList.put(vr.getId(), vrData);
+        }
+        return new ArrayList<StoragePoolForMigrationResponse>(vrDataList.values());
+    }
+
 
     public static List<AccountResponse> createAccountResponse(AccountJoinVO... accounts) {
         List<AccountResponse> respList = new ArrayList<AccountResponse>();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/dao/HostJoinDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/HostJoinDao.java b/server/src/com/cloud/api/query/dao/HostJoinDao.java
index 1a21299..f526ca3 100644
--- a/server/src/com/cloud/api/query/dao/HostJoinDao.java
+++ b/server/src/com/cloud/api/query/dao/HostJoinDao.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.cloudstack.api.ApiConstants.HostDetails;
 import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import com.cloud.api.query.vo.HostJoinVO;
 import com.cloud.host.Host;
 import com.cloud.utils.db.GenericDao;
@@ -31,6 +32,10 @@ public interface HostJoinDao extends GenericDao<HostJoinVO, Long> {
 
     HostResponse setHostResponse(HostResponse response, HostJoinVO host);
 
+    HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, EnumSet<HostDetails> details);
+
+    HostForMigrationResponse setHostForMigrationResponse(HostForMigrationResponse response, HostJoinVO host);
+
     List<HostJoinVO> newHostView(Host group);
 
     List<HostJoinVO> searchByIds(Long... ids);


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

Posted by ts...@apache.org.
CS-1879: NPE while migrating volume. The state transitions on the volume that has to be migrated were incorrect. A volume to be migrated is in ready state and cannot be transitioned to copying state. Similarly, the duplicated volume is in ready state too and cannot be transitioned to creating state. Fixed it by transitioning the volume to migrating state when a migrateVolume api call is made. Also, a volume has to be destroyed first before it can be expunged. Fixed that too.

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/b01f6312
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/b01f6312
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/b01f6312

Branch: refs/heads/marvin_refactor
Commit: b01f63123fff00fe40cdd46d741f29dec05fcc8d
Parents: f98ce5d
Author: Devdeep Singh <de...@gmail.com>
Authored: Fri Apr 19 14:43:55 2013 +0530
Committer: Abhinandan Prateek <ap...@apache.org>
Committed: Fri Apr 19 16:15:24 2013 +0530

----------------------------------------------------------------------
 .../storage/volume/VolumeServiceImpl.java          |    8 ++++++--
 1 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/b01f6312/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
index e3526de..b39502b 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java
@@ -521,8 +521,8 @@ public class VolumeServiceImpl implements VolumeService {
 
             VolumeVO destVol = duplicateVolumeOnAnotherStorage(srcVolume, (StoragePool)destStore);
             VolumeInfo destVolume = this.volFactory.getVolume(destVol.getId(), destStore);
-            destVolume.processEvent(Event.CreateOnlyRequested);
-            srcVolume.processEvent(Event.CopyingRequested);
+            destVolume.processEvent(Event.MigrationRequested);
+            srcVolume.processEvent(Event.MigrationRequested);
 
             CopyVolumeContext<VolumeApiResult> context = new CopyVolumeContext<VolumeApiResult>(null, future, srcVolume, 
                     destVolume,
@@ -550,6 +550,8 @@ public class VolumeServiceImpl implements VolumeService {
                 res.setResult(result.getResult());
                 destVolume.processEvent(Event.OperationFailed);
                 srcVolume.processEvent(Event.OperationFailed);
+                destroyVolume(destVolume.getId());
+                destVolume = this.volFactory.getVolume(destVolume.getId());
                 AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(destVolume);
                 destroyFuture.get();
                 future.complete(res);
@@ -557,6 +559,8 @@ public class VolumeServiceImpl implements VolumeService {
             }
             srcVolume.processEvent(Event.OperationSuccessed);
             destVolume.processEvent(Event.OperationSuccessed);
+            destroyVolume(srcVolume.getId());
+            srcVolume = this.volFactory.getVolume(srcVolume.getId());
             AsyncCallFuture<VolumeApiResult> destroyFuture = this.expungeVolumeAsync(srcVolume);
             destroyFuture.get();
             future.complete(res);


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

Posted by ts...@apache.org.
call the EntityFactory simply factory


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

Branch: refs/heads/marvin_refactor
Commit: d915fb22aa5c2a19d0d3eacdd013323e73ec2baf
Parents: 94b18c6
Author: Prasanna Santhanam <ts...@apache.org>
Authored: Thu Apr 18 17:29:48 2013 +0530
Committer: Prasanna Santhanam <ts...@apache.org>
Committed: Thu Apr 18 17:29:48 2013 +0530

----------------------------------------------------------------------
 .../marvin/marvin/integration/lib/base/Account.py  |    4 ++--
 .../marvin/integration/lib/base/AutoScalePolicy.py |    4 ++--
 .../integration/lib/base/AutoScaleVmGroup.py       |    4 ++--
 .../integration/lib/base/AutoScaleVmProfile.py     |    4 ++--
 .../integration/lib/base/CloudStackEntity.py       |    2 +-
 .../marvin/integration/lib/base/Condition.py       |    4 ++--
 .../marvin/marvin/integration/lib/base/Counter.py  |    4 ++--
 .../marvin/integration/lib/base/DiskOffering.py    |    4 ++--
 tools/marvin/marvin/integration/lib/base/Domain.py |    4 ++--
 .../integration/lib/base/EgressFirewallRule.py     |    4 ++--
 .../marvin/integration/lib/base/FirewallRule.py    |    4 ++--
 .../integration/lib/base/GlobalLoadBalancerRule.py |    6 +++---
 .../marvin/integration/lib/base/InstanceGroup.py   |    4 ++--
 .../integration/lib/base/IpForwardingRule.py       |    4 ++--
 .../integration/lib/base/LBHealthCheckPolicy.py    |    4 ++--
 .../integration/lib/base/LBStickinessPolicy.py     |    4 ++--
 .../integration/lib/base/LoadBalancerRule.py       |    4 ++--
 .../marvin/marvin/integration/lib/base/Network.py  |    4 ++--
 .../marvin/integration/lib/base/NetworkACL.py      |    4 ++--
 .../marvin/integration/lib/base/NetworkOffering.py |    4 ++--
 .../marvin/integration/lib/base/PhysicalNetwork.py |    4 ++--
 tools/marvin/marvin/integration/lib/base/Pod.py    |    4 ++--
 .../integration/lib/base/PortForwardingRule.py     |    4 ++--
 .../marvin/integration/lib/base/PrivateGateway.py  |    4 ++--
 .../marvin/marvin/integration/lib/base/Project.py  |    4 ++--
 .../marvin/integration/lib/base/RemoteAccessVpn.py |    4 ++--
 .../marvin/integration/lib/base/SSHKeyPair.py      |    4 ++--
 .../marvin/integration/lib/base/SecurityGroup.py   |    4 ++--
 .../marvin/integration/lib/base/ServiceOffering.py |    4 ++--
 .../marvin/marvin/integration/lib/base/Snapshot.py |    4 ++--
 .../marvin/integration/lib/base/SnapshotPolicy.py  |    4 ++--
 .../marvin/integration/lib/base/StaticRoute.py     |    4 ++--
 .../integration/lib/base/StorageNetworkIpRange.py  |    4 ++--
 .../marvin/integration/lib/base/StoragePool.py     |    4 ++--
 tools/marvin/marvin/integration/lib/base/Tags.py   |    4 ++--
 .../marvin/marvin/integration/lib/base/Template.py |    4 ++--
 tools/marvin/marvin/integration/lib/base/User.py   |    4 ++--
 .../marvin/integration/lib/base/VMSnapshot.py      |    4 ++--
 tools/marvin/marvin/integration/lib/base/VPC.py    |    4 ++--
 .../marvin/integration/lib/base/VPCOffering.py     |    4 ++--
 .../marvin/integration/lib/base/VirtualMachine.py  |    4 ++--
 .../integration/lib/base/VirtualRouterElement.py   |    4 ++--
 .../marvin/integration/lib/base/VlanIpRange.py     |    4 ++--
 tools/marvin/marvin/integration/lib/base/Volume.py |    4 ++--
 .../marvin/integration/lib/base/VpnConnection.py   |    4 ++--
 .../integration/lib/base/VpnCustomerGateway.py     |    4 ++--
 .../marvin/integration/lib/base/VpnGateway.py      |    4 ++--
 tools/marvin/marvin/integration/lib/base/Zone.py   |    4 ++--
 .../marvin/marvin/integration/lib/base/__init__.py |    2 +-
 49 files changed, 97 insertions(+), 97 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Account.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Account.py b/tools/marvin/marvin/integration/lib/base/Account.py
index 63df1dc..8a160c3 100644
--- a/tools/marvin/marvin/integration/lib/base/Account.py
+++ b/tools/marvin/marvin/integration/lib/base/Account.py
@@ -50,9 +50,9 @@ class Account(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, AccountFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createAccount.createAccountCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in AccountFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         account = apiclient.createAccount(cmd)
         return Account(account.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/AutoScalePolicy.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/AutoScalePolicy.py b/tools/marvin/marvin/integration/lib/base/AutoScalePolicy.py
index d3dcd3d..b484702 100644
--- a/tools/marvin/marvin/integration/lib/base/AutoScalePolicy.py
+++ b/tools/marvin/marvin/integration/lib/base/AutoScalePolicy.py
@@ -28,9 +28,9 @@ class AutoScalePolicy(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, AutoScalePolicyFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createAutoScalePolicy.createAutoScalePolicyCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in AutoScalePolicyFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         autoscalepolicy = apiclient.createAutoScalePolicy(cmd)
         return AutoScalePolicy(autoscalepolicy.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/AutoScaleVmGroup.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/AutoScaleVmGroup.py b/tools/marvin/marvin/integration/lib/base/AutoScaleVmGroup.py
index ca6734c..08fd579 100644
--- a/tools/marvin/marvin/integration/lib/base/AutoScaleVmGroup.py
+++ b/tools/marvin/marvin/integration/lib/base/AutoScaleVmGroup.py
@@ -38,9 +38,9 @@ class AutoScaleVmGroup(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, AutoScaleVmGroupFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createAutoScaleVmGroup.createAutoScaleVmGroupCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in AutoScaleVmGroupFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         autoscalevmgroup = apiclient.createAutoScaleVmGroup(cmd)
         return AutoScaleVmGroup(autoscalevmgroup.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/AutoScaleVmProfile.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/AutoScaleVmProfile.py b/tools/marvin/marvin/integration/lib/base/AutoScaleVmProfile.py
index 6a3328a..eefac8e 100644
--- a/tools/marvin/marvin/integration/lib/base/AutoScaleVmProfile.py
+++ b/tools/marvin/marvin/integration/lib/base/AutoScaleVmProfile.py
@@ -28,9 +28,9 @@ class AutoScaleVmProfile(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, AutoScaleVmProfileFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createAutoScaleVmProfile.createAutoScaleVmProfileCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in AutoScaleVmProfileFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         autoscalevmprofile = apiclient.createAutoScaleVmProfile(cmd)
         return AutoScaleVmProfile(autoscalevmprofile.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/CloudStackEntity.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/CloudStackEntity.py b/tools/marvin/marvin/integration/lib/base/CloudStackEntity.py
index afab852..879506c 100644
--- a/tools/marvin/marvin/integration/lib/base/CloudStackEntity.py
+++ b/tools/marvin/marvin/integration/lib/base/CloudStackEntity.py
@@ -22,4 +22,4 @@ class CloudStackEntity(object):
     __version__ = cloudstack_version
 
     def getVersion(self):
-        return self.__version__
\ No newline at end of file
+        return self.__version__

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Condition.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Condition.py b/tools/marvin/marvin/integration/lib/base/Condition.py
index 6ab4a4e..0fcb7b0 100644
--- a/tools/marvin/marvin/integration/lib/base/Condition.py
+++ b/tools/marvin/marvin/integration/lib/base/Condition.py
@@ -27,9 +27,9 @@ class Condition(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, ConditionFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createCondition.createConditionCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in ConditionFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         condition = apiclient.createCondition(cmd)
         return Condition(condition.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Counter.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Counter.py b/tools/marvin/marvin/integration/lib/base/Counter.py
index ff60117..4c68ccf 100644
--- a/tools/marvin/marvin/integration/lib/base/Counter.py
+++ b/tools/marvin/marvin/integration/lib/base/Counter.py
@@ -27,9 +27,9 @@ class Counter(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, CounterFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createCounter.createCounterCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in CounterFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         counter = apiclient.createCounter(cmd)
         return Counter(counter.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/DiskOffering.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/DiskOffering.py b/tools/marvin/marvin/integration/lib/base/DiskOffering.py
index d1c4c5a..1ad68df 100644
--- a/tools/marvin/marvin/integration/lib/base/DiskOffering.py
+++ b/tools/marvin/marvin/integration/lib/base/DiskOffering.py
@@ -28,9 +28,9 @@ class DiskOffering(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, DiskOfferingFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createDiskOffering.createDiskOfferingCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in DiskOfferingFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         diskoffering = apiclient.createDiskOffering(cmd)
         return DiskOffering(diskoffering.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Domain.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Domain.py b/tools/marvin/marvin/integration/lib/base/Domain.py
index c3d7a3c..215169e 100644
--- a/tools/marvin/marvin/integration/lib/base/Domain.py
+++ b/tools/marvin/marvin/integration/lib/base/Domain.py
@@ -28,9 +28,9 @@ class Domain(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, DomainFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createDomain.createDomainCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in DomainFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         domain = apiclient.createDomain(cmd)
         return Domain(domain.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/EgressFirewallRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/EgressFirewallRule.py b/tools/marvin/marvin/integration/lib/base/EgressFirewallRule.py
index 890fc53..4d4e5bc 100644
--- a/tools/marvin/marvin/integration/lib/base/EgressFirewallRule.py
+++ b/tools/marvin/marvin/integration/lib/base/EgressFirewallRule.py
@@ -27,9 +27,9 @@ class EgressFirewallRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, EgressFirewallRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createEgressFirewallRule.createEgressFirewallRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in EgressFirewallRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         egressfirewallrule = apiclient.createEgressFirewallRule(cmd)
         return EgressFirewallRule(egressfirewallrule.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/FirewallRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/FirewallRule.py b/tools/marvin/marvin/integration/lib/base/FirewallRule.py
index 713e34f..4c895fc 100644
--- a/tools/marvin/marvin/integration/lib/base/FirewallRule.py
+++ b/tools/marvin/marvin/integration/lib/base/FirewallRule.py
@@ -27,9 +27,9 @@ class FirewallRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, FirewallRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createFirewallRule.createFirewallRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in FirewallRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         firewallrule = apiclient.createFirewallRule(cmd)
         return FirewallRule(firewallrule.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/GlobalLoadBalancerRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/GlobalLoadBalancerRule.py b/tools/marvin/marvin/integration/lib/base/GlobalLoadBalancerRule.py
index dbb821e..e2ffbf8 100644
--- a/tools/marvin/marvin/integration/lib/base/GlobalLoadBalancerRule.py
+++ b/tools/marvin/marvin/integration/lib/base/GlobalLoadBalancerRule.py
@@ -30,9 +30,9 @@ class GlobalLoadBalancerRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, GlobalLoadBalancerRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createGlobalLoadBalancerRule.createGlobalLoadBalancerRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in GlobalLoadBalancerRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         globalloadbalancerrule = apiclient.createGlobalLoadBalancerRule(cmd)
         return GlobalLoadBalancerRule(globalloadbalancerrule.__dict__)
@@ -77,4 +77,4 @@ class GlobalLoadBalancerRule(CloudStackEntity.CloudStackEntity):
         cmd.loadbalancerrulelist = loadbalancerrulelist
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         togloballoadbalancerrule = apiclient.assignToGlobalLoadBalancerRule(cmd)
-        return togloballoadbalancerrule
\ No newline at end of file
+        return togloballoadbalancerrule

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/InstanceGroup.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/InstanceGroup.py b/tools/marvin/marvin/integration/lib/base/InstanceGroup.py
index 3c4148b..36a6a52 100644
--- a/tools/marvin/marvin/integration/lib/base/InstanceGroup.py
+++ b/tools/marvin/marvin/integration/lib/base/InstanceGroup.py
@@ -28,9 +28,9 @@ class InstanceGroup(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, InstanceGroupFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createInstanceGroup.createInstanceGroupCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in InstanceGroupFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         instancegroup = apiclient.createInstanceGroup(cmd)
         return InstanceGroup(instancegroup.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/IpForwardingRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/IpForwardingRule.py b/tools/marvin/marvin/integration/lib/base/IpForwardingRule.py
index c4103fe..8dc68ea 100644
--- a/tools/marvin/marvin/integration/lib/base/IpForwardingRule.py
+++ b/tools/marvin/marvin/integration/lib/base/IpForwardingRule.py
@@ -27,9 +27,9 @@ class IpForwardingRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, IpForwardingRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createIpForwardingRule.createIpForwardingRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in IpForwardingRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         ipforwardingrule = apiclient.createIpForwardingRule(cmd)
         return IpForwardingRule(ipforwardingrule.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/LBHealthCheckPolicy.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/LBHealthCheckPolicy.py b/tools/marvin/marvin/integration/lib/base/LBHealthCheckPolicy.py
index 5527a1c..b2eb692 100644
--- a/tools/marvin/marvin/integration/lib/base/LBHealthCheckPolicy.py
+++ b/tools/marvin/marvin/integration/lib/base/LBHealthCheckPolicy.py
@@ -27,9 +27,9 @@ class LBHealthCheckPolicy(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, LBHealthCheckPolicyFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createLBHealthCheckPolicy.createLBHealthCheckPolicyCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in LBHealthCheckPolicyFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         lbhealthcheckpolicy = apiclient.createLBHealthCheckPolicy(cmd)
         return LBHealthCheckPolicy(lbhealthcheckpolicy.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/LBStickinessPolicy.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/LBStickinessPolicy.py b/tools/marvin/marvin/integration/lib/base/LBStickinessPolicy.py
index 1346f58..1397637 100644
--- a/tools/marvin/marvin/integration/lib/base/LBStickinessPolicy.py
+++ b/tools/marvin/marvin/integration/lib/base/LBStickinessPolicy.py
@@ -27,9 +27,9 @@ class LBStickinessPolicy(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, LBStickinessPolicyFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createLBStickinessPolicy.createLBStickinessPolicyCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in LBStickinessPolicyFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         lbstickinesspolicy = apiclient.createLBStickinessPolicy(cmd)
         return LBStickinessPolicy(lbstickinesspolicy.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/LoadBalancerRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/LoadBalancerRule.py b/tools/marvin/marvin/integration/lib/base/LoadBalancerRule.py
index 1b5f1e3..4873982 100644
--- a/tools/marvin/marvin/integration/lib/base/LoadBalancerRule.py
+++ b/tools/marvin/marvin/integration/lib/base/LoadBalancerRule.py
@@ -31,9 +31,9 @@ class LoadBalancerRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, LoadBalancerRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createLoadBalancerRule.createLoadBalancerRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in LoadBalancerRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         loadbalancerrule = apiclient.createLoadBalancerRule(cmd)
         return LoadBalancerRule(loadbalancerrule.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Network.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Network.py b/tools/marvin/marvin/integration/lib/base/Network.py
index 6cfa828..27fc84b 100644
--- a/tools/marvin/marvin/integration/lib/base/Network.py
+++ b/tools/marvin/marvin/integration/lib/base/Network.py
@@ -29,9 +29,9 @@ class Network(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, NetworkFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createNetwork.createNetworkCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in NetworkFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         network = apiclient.createNetwork(cmd)
         return Network(network.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/NetworkACL.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/NetworkACL.py b/tools/marvin/marvin/integration/lib/base/NetworkACL.py
index 2102eb1..9f360f9 100644
--- a/tools/marvin/marvin/integration/lib/base/NetworkACL.py
+++ b/tools/marvin/marvin/integration/lib/base/NetworkACL.py
@@ -27,9 +27,9 @@ class NetworkACL(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, NetworkACLFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createNetworkACL.createNetworkACLCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in NetworkACLFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         networkacl = apiclient.createNetworkACL(cmd)
         return NetworkACL(networkacl.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/NetworkOffering.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/NetworkOffering.py b/tools/marvin/marvin/integration/lib/base/NetworkOffering.py
index a22d85c..fd8cc1d 100644
--- a/tools/marvin/marvin/integration/lib/base/NetworkOffering.py
+++ b/tools/marvin/marvin/integration/lib/base/NetworkOffering.py
@@ -28,9 +28,9 @@ class NetworkOffering(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, NetworkOfferingFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createNetworkOffering.createNetworkOfferingCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in NetworkOfferingFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         networkoffering = apiclient.createNetworkOffering(cmd)
         return NetworkOffering(networkoffering.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/PhysicalNetwork.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/PhysicalNetwork.py b/tools/marvin/marvin/integration/lib/base/PhysicalNetwork.py
index 329393a..60e3609 100644
--- a/tools/marvin/marvin/integration/lib/base/PhysicalNetwork.py
+++ b/tools/marvin/marvin/integration/lib/base/PhysicalNetwork.py
@@ -28,9 +28,9 @@ class PhysicalNetwork(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, PhysicalNetworkFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createPhysicalNetwork.createPhysicalNetworkCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in PhysicalNetworkFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         physicalnetwork = apiclient.createPhysicalNetwork(cmd)
         return PhysicalNetwork(physicalnetwork.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Pod.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Pod.py b/tools/marvin/marvin/integration/lib/base/Pod.py
index 9d8d885..fdaea33 100644
--- a/tools/marvin/marvin/integration/lib/base/Pod.py
+++ b/tools/marvin/marvin/integration/lib/base/Pod.py
@@ -28,9 +28,9 @@ class Pod(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, PodFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createPod.createPodCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in PodFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         pod = apiclient.createPod(cmd)
         return Pod(pod.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/PortForwardingRule.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/PortForwardingRule.py b/tools/marvin/marvin/integration/lib/base/PortForwardingRule.py
index 9cf58d9..8bf684a 100644
--- a/tools/marvin/marvin/integration/lib/base/PortForwardingRule.py
+++ b/tools/marvin/marvin/integration/lib/base/PortForwardingRule.py
@@ -28,9 +28,9 @@ class PortForwardingRule(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, PortForwardingRuleFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createPortForwardingRule.createPortForwardingRuleCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in PortForwardingRuleFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         portforwardingrule = apiclient.createPortForwardingRule(cmd)
         return PortForwardingRule(portforwardingrule.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/PrivateGateway.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/PrivateGateway.py b/tools/marvin/marvin/integration/lib/base/PrivateGateway.py
index 707c33f..6cec55a 100644
--- a/tools/marvin/marvin/integration/lib/base/PrivateGateway.py
+++ b/tools/marvin/marvin/integration/lib/base/PrivateGateway.py
@@ -27,9 +27,9 @@ class PrivateGateway(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, PrivateGatewayFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createPrivateGateway.createPrivateGatewayCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in PrivateGatewayFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         privategateway = apiclient.createPrivateGateway(cmd)
         return PrivateGateway(privategateway.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Project.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Project.py b/tools/marvin/marvin/integration/lib/base/Project.py
index 243d22d..1fc5b53 100644
--- a/tools/marvin/marvin/integration/lib/base/Project.py
+++ b/tools/marvin/marvin/integration/lib/base/Project.py
@@ -41,9 +41,9 @@ class Project(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, ProjectFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createProject.createProjectCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in ProjectFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         project = apiclient.createProject(cmd)
         return Project(project.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/RemoteAccessVpn.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/RemoteAccessVpn.py b/tools/marvin/marvin/integration/lib/base/RemoteAccessVpn.py
index 339d706..2c460bc 100644
--- a/tools/marvin/marvin/integration/lib/base/RemoteAccessVpn.py
+++ b/tools/marvin/marvin/integration/lib/base/RemoteAccessVpn.py
@@ -27,9 +27,9 @@ class RemoteAccessVpn(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, RemoteAccessVpnFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in RemoteAccessVpnFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         remoteaccessvpn = apiclient.createRemoteAccessVpn(cmd)
         return RemoteAccessVpn(remoteaccessvpn.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/SSHKeyPair.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/SSHKeyPair.py b/tools/marvin/marvin/integration/lib/base/SSHKeyPair.py
index f080455..6d1e5ef 100644
--- a/tools/marvin/marvin/integration/lib/base/SSHKeyPair.py
+++ b/tools/marvin/marvin/integration/lib/base/SSHKeyPair.py
@@ -28,9 +28,9 @@ class SSHKeyPair(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, SSHKeyPairFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createSSHKeyPair.createSSHKeyPairCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in SSHKeyPairFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         sshkeypair = apiclient.createSSHKeyPair(cmd)
         return SSHKeyPair(sshkeypair.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/SecurityGroup.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/SecurityGroup.py b/tools/marvin/marvin/integration/lib/base/SecurityGroup.py
index e532eef..e4bb53b 100644
--- a/tools/marvin/marvin/integration/lib/base/SecurityGroup.py
+++ b/tools/marvin/marvin/integration/lib/base/SecurityGroup.py
@@ -31,9 +31,9 @@ class SecurityGroup(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, SecurityGroupFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createSecurityGroup.createSecurityGroupCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in SecurityGroupFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         securitygroup = apiclient.createSecurityGroup(cmd)
         return SecurityGroup(securitygroup.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/ServiceOffering.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/ServiceOffering.py b/tools/marvin/marvin/integration/lib/base/ServiceOffering.py
index fab516c..bf5df76 100644
--- a/tools/marvin/marvin/integration/lib/base/ServiceOffering.py
+++ b/tools/marvin/marvin/integration/lib/base/ServiceOffering.py
@@ -28,9 +28,9 @@ class ServiceOffering(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, ServiceOfferingFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createServiceOffering.createServiceOfferingCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in ServiceOfferingFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         serviceoffering = apiclient.createServiceOffering(cmd)
         return ServiceOffering(serviceoffering.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Snapshot.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Snapshot.py b/tools/marvin/marvin/integration/lib/base/Snapshot.py
index 1739b9c..1dde1b4 100644
--- a/tools/marvin/marvin/integration/lib/base/Snapshot.py
+++ b/tools/marvin/marvin/integration/lib/base/Snapshot.py
@@ -27,9 +27,9 @@ class Snapshot(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, SnapshotFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createSnapshot.createSnapshotCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in SnapshotFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         snapshot = apiclient.createSnapshot(cmd)
         return Snapshot(snapshot.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/SnapshotPolicy.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/SnapshotPolicy.py b/tools/marvin/marvin/integration/lib/base/SnapshotPolicy.py
index d18c4ba..a3ef2f8 100644
--- a/tools/marvin/marvin/integration/lib/base/SnapshotPolicy.py
+++ b/tools/marvin/marvin/integration/lib/base/SnapshotPolicy.py
@@ -27,9 +27,9 @@ class SnapshotPolicy(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, SnapshotPolicyFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createSnapshotPolicy.createSnapshotPolicyCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in SnapshotPolicyFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         snapshotpolicy = apiclient.createSnapshotPolicy(cmd)
         return SnapshotPolicy(snapshotpolicy.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/StaticRoute.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/StaticRoute.py b/tools/marvin/marvin/integration/lib/base/StaticRoute.py
index 817e7a0..4ccf546 100644
--- a/tools/marvin/marvin/integration/lib/base/StaticRoute.py
+++ b/tools/marvin/marvin/integration/lib/base/StaticRoute.py
@@ -27,9 +27,9 @@ class StaticRoute(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, StaticRouteFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createStaticRoute.createStaticRouteCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in StaticRouteFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         staticroute = apiclient.createStaticRoute(cmd)
         return StaticRoute(staticroute.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/StorageNetworkIpRange.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/StorageNetworkIpRange.py b/tools/marvin/marvin/integration/lib/base/StorageNetworkIpRange.py
index 1324eb0..666a9d2 100644
--- a/tools/marvin/marvin/integration/lib/base/StorageNetworkIpRange.py
+++ b/tools/marvin/marvin/integration/lib/base/StorageNetworkIpRange.py
@@ -28,9 +28,9 @@ class StorageNetworkIpRange(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, StorageNetworkIpRangeFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createStorageNetworkIpRange.createStorageNetworkIpRangeCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in StorageNetworkIpRangeFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         storagenetworkiprange = apiclient.createStorageNetworkIpRange(cmd)
         return StorageNetworkIpRange(storagenetworkiprange.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/StoragePool.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/StoragePool.py b/tools/marvin/marvin/integration/lib/base/StoragePool.py
index e359c9a..8b4bd4a 100644
--- a/tools/marvin/marvin/integration/lib/base/StoragePool.py
+++ b/tools/marvin/marvin/integration/lib/base/StoragePool.py
@@ -30,9 +30,9 @@ class StoragePool(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, StoragePoolFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createStoragePool.createStoragePoolCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in StoragePoolFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         storagepool = apiclient.createStoragePool(cmd)
         return StoragePool(storagepool.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Tags.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Tags.py b/tools/marvin/marvin/integration/lib/base/Tags.py
index 24ba720..c68a664 100644
--- a/tools/marvin/marvin/integration/lib/base/Tags.py
+++ b/tools/marvin/marvin/integration/lib/base/Tags.py
@@ -27,9 +27,9 @@ class Tags(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, TagsFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createTags.createTagsCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in TagsFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         tags = apiclient.createTags(cmd)
         return Tags(tags.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Template.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Template.py b/tools/marvin/marvin/integration/lib/base/Template.py
index 11ab641..36f6bf4 100644
--- a/tools/marvin/marvin/integration/lib/base/Template.py
+++ b/tools/marvin/marvin/integration/lib/base/Template.py
@@ -42,9 +42,9 @@ class Template(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, TemplateFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createTemplate.createTemplateCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in TemplateFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         template = apiclient.createTemplate(cmd)
         return Template(template.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/User.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/User.py b/tools/marvin/marvin/integration/lib/base/User.py
index 0cf3978..e10d4f3 100644
--- a/tools/marvin/marvin/integration/lib/base/User.py
+++ b/tools/marvin/marvin/integration/lib/base/User.py
@@ -58,9 +58,9 @@ class User(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, UserFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createUser.createUserCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in UserFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         user = apiclient.createUser(cmd)
         return User(user.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VMSnapshot.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VMSnapshot.py b/tools/marvin/marvin/integration/lib/base/VMSnapshot.py
index e7f2e9a..570365a 100644
--- a/tools/marvin/marvin/integration/lib/base/VMSnapshot.py
+++ b/tools/marvin/marvin/integration/lib/base/VMSnapshot.py
@@ -27,9 +27,9 @@ class VMSnapshot(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VMSnapshotFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVMSnapshot.createVMSnapshotCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VMSnapshotFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vmsnapshot = apiclient.createVMSnapshot(cmd)
         return VMSnapshot(vmsnapshot.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VPC.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VPC.py b/tools/marvin/marvin/integration/lib/base/VPC.py
index e79a769..b3ae25d 100644
--- a/tools/marvin/marvin/integration/lib/base/VPC.py
+++ b/tools/marvin/marvin/integration/lib/base/VPC.py
@@ -29,9 +29,9 @@ class VPC(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VPCFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVPC.createVPCCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VPCFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vpc = apiclient.createVPC(cmd)
         return VPC(vpc.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VPCOffering.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VPCOffering.py b/tools/marvin/marvin/integration/lib/base/VPCOffering.py
index 059426e..842afec 100644
--- a/tools/marvin/marvin/integration/lib/base/VPCOffering.py
+++ b/tools/marvin/marvin/integration/lib/base/VPCOffering.py
@@ -28,9 +28,9 @@ class VPCOffering(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VPCOfferingFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVPCOffering.createVPCOfferingCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VPCOfferingFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vpcoffering = apiclient.createVPCOffering(cmd)
         return VPCOffering(vpcoffering.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VirtualMachine.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VirtualMachine.py b/tools/marvin/marvin/integration/lib/base/VirtualMachine.py
index 0d2fd44..a0193cb 100644
--- a/tools/marvin/marvin/integration/lib/base/VirtualMachine.py
+++ b/tools/marvin/marvin/integration/lib/base/VirtualMachine.py
@@ -58,9 +58,9 @@ class VirtualMachine(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def deploy(cls, apiclient, VirtualMachineFactory, **kwargs):
+    def deploy(cls, apiclient, factory, **kwargs):
         cmd = deployVirtualMachine.deployVirtualMachineCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VirtualMachineFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         virtualmachine = apiclient.deployVirtualMachine(cmd)
         return VirtualMachine(virtualmachine.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VirtualRouterElement.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VirtualRouterElement.py b/tools/marvin/marvin/integration/lib/base/VirtualRouterElement.py
index f22e7ee..669298e 100644
--- a/tools/marvin/marvin/integration/lib/base/VirtualRouterElement.py
+++ b/tools/marvin/marvin/integration/lib/base/VirtualRouterElement.py
@@ -27,9 +27,9 @@ class VirtualRouterElement(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VirtualRouterElementFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVirtualRouterElement.createVirtualRouterElementCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VirtualRouterElementFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         virtualrouterelement = apiclient.createVirtualRouterElement(cmd)
         return VirtualRouterElement(virtualrouterelement.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VlanIpRange.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VlanIpRange.py b/tools/marvin/marvin/integration/lib/base/VlanIpRange.py
index 7e444f5..2bc11d5 100644
--- a/tools/marvin/marvin/integration/lib/base/VlanIpRange.py
+++ b/tools/marvin/marvin/integration/lib/base/VlanIpRange.py
@@ -27,9 +27,9 @@ class VlanIpRange(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VlanIpRangeFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVlanIpRange.createVlanIpRangeCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VlanIpRangeFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vlaniprange = apiclient.createVlanIpRange(cmd)
         return VlanIpRange(vlaniprange.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Volume.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Volume.py b/tools/marvin/marvin/integration/lib/base/Volume.py
index 4359348..2f4831f 100644
--- a/tools/marvin/marvin/integration/lib/base/Volume.py
+++ b/tools/marvin/marvin/integration/lib/base/Volume.py
@@ -42,9 +42,9 @@ class Volume(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VolumeFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVolume.createVolumeCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VolumeFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         volume = apiclient.createVolume(cmd)
         return Volume(volume.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VpnConnection.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VpnConnection.py b/tools/marvin/marvin/integration/lib/base/VpnConnection.py
index 497a239..1fb889e 100644
--- a/tools/marvin/marvin/integration/lib/base/VpnConnection.py
+++ b/tools/marvin/marvin/integration/lib/base/VpnConnection.py
@@ -36,9 +36,9 @@ class VpnConnection(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VpnConnectionFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVpnConnection.createVpnConnectionCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VpnConnectionFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vpnconnection = apiclient.createVpnConnection(cmd)
         return VpnConnection(vpnconnection.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VpnCustomerGateway.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VpnCustomerGateway.py b/tools/marvin/marvin/integration/lib/base/VpnCustomerGateway.py
index 69fe2c6..f80b18c 100644
--- a/tools/marvin/marvin/integration/lib/base/VpnCustomerGateway.py
+++ b/tools/marvin/marvin/integration/lib/base/VpnCustomerGateway.py
@@ -28,9 +28,9 @@ class VpnCustomerGateway(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VpnCustomerGatewayFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVpnCustomerGateway.createVpnCustomerGatewayCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VpnCustomerGatewayFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vpncustomergateway = apiclient.createVpnCustomerGateway(cmd)
         return VpnCustomerGateway(vpncustomergateway.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/VpnGateway.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/VpnGateway.py b/tools/marvin/marvin/integration/lib/base/VpnGateway.py
index aa8a7aa..6ae6c14 100644
--- a/tools/marvin/marvin/integration/lib/base/VpnGateway.py
+++ b/tools/marvin/marvin/integration/lib/base/VpnGateway.py
@@ -27,9 +27,9 @@ class VpnGateway(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, VpnGatewayFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createVpnGateway.createVpnGatewayCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in VpnGatewayFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         vpngateway = apiclient.createVpnGateway(cmd)
         return VpnGateway(vpngateway.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/Zone.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/Zone.py b/tools/marvin/marvin/integration/lib/base/Zone.py
index 26527cf..918b031 100644
--- a/tools/marvin/marvin/integration/lib/base/Zone.py
+++ b/tools/marvin/marvin/integration/lib/base/Zone.py
@@ -28,9 +28,9 @@ class Zone(CloudStackEntity.CloudStackEntity):
 
 
     @classmethod
-    def create(cls, apiclient, ZoneFactory, **kwargs):
+    def create(cls, apiclient, factory, **kwargs):
         cmd = createZone.createZoneCmd()
-        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in ZoneFactory.__dict__.iteritems()]
+        [setattr(cmd, factoryKey, factoryValue) for factoryKey, factoryValue in factory.__dict__.iteritems()]
         [setattr(cmd, key, value) for key,value in kwargs.iteritems()]
         zone = apiclient.createZone(cmd)
         return Zone(zone.__dict__)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d915fb22/tools/marvin/marvin/integration/lib/base/__init__.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base/__init__.py b/tools/marvin/marvin/integration/lib/base/__init__.py
index d216be4..13a8339 100644
--- a/tools/marvin/marvin/integration/lib/base/__init__.py
+++ b/tools/marvin/marvin/integration/lib/base/__init__.py
@@ -13,4 +13,4 @@
 # "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.
\ No newline at end of file
+# under the License.


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

Posted by ts...@apache.org.
CSS: Cleanup formatting


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

Branch: refs/heads/marvin_refactor
Commit: 977162b9f09436f08c7139e43ec63826a47ef7f9
Parents: d51d596
Author: Brian Federle <br...@citrix.com>
Authored: Thu Apr 18 15:16:49 2013 -0700
Committer: Brian Federle <br...@citrix.com>
Committed: Thu Apr 18 15:16:49 2013 -0700

----------------------------------------------------------------------
 ui/css/cloudstack3.css |    7 +++----
 1 files changed, 3 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/977162b9/ui/css/cloudstack3.css
----------------------------------------------------------------------
diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css
index 18d86b7..d4c670c 100644
--- a/ui/css/cloudstack3.css
+++ b/ui/css/cloudstack3.css
@@ -11776,12 +11776,11 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
 .updateResourceLimits:hover .icon {
   background-position: -100px -614px;
 }
- 
+
 .addVlanRange .icon {
   background-position: -168px -31px;
 }
 
-
 .addVlanRange:hover .icon {
   background-position: -168px -613px;
 }
@@ -11811,8 +11810,8 @@ div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-it
   background-position: -168px -31px;
 }
 
-.reset .icon ,
-.scaleUp .icon{
+.reset .icon,
+.scaleUp .icon {
   background-position: -168px -31px;
 }
 


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

Posted by ts...@apache.org.
Merge branch 'master' into marvin_refactor


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

Branch: refs/heads/marvin_refactor
Commit: 4abd92922803bb92e08162ec049a7b7e365424cb
Parents: da464aa b01f631
Author: Prasanna Santhanam <ts...@apache.org>
Authored: Fri Apr 19 16:57:41 2013 +0530
Committer: Prasanna Santhanam <ts...@apache.org>
Committed: Fri Apr 19 16:57:41 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 +
 .../api/command/admin/config/ListCfgsByCmd.java    |   24 +-
 .../api/command/admin/config/UpdateCfgCmd.java     |   22 +-
 .../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/ConfigurationResponse.java        |   12 +
 .../api/response/HostForMigrationResponse.java     |  365 +++++++++++++++
 .../cloudstack/api/response/HostResponse.java      |    1 -
 .../response/StoragePoolForMigrationResponse.java  |  248 ++++++++++
 .../api/response/StoragePoolResponse.java          |    3 -
 .../api/command/test/ListCfgCmdTest.java           |   89 ++++
 .../api/command/test/UpdateCfgCmdTest.java         |  116 +++++
 client/tomcatconf/applicationContext.xml.in        |    1 +
 client/tomcatconf/commands.properties.in           |    3 +
 .../cloud/hypervisor/HypervisorCapabilitiesVO.java |   24 +-
 docs/en-US/Release_Notes.xml                       |  270 +++++++++--
 .../api/storage/ObjectInDataStoreStateMachine.java |    2 +
 .../subsystem/api/storage/VolumeService.java       |    7 +-
 .../datastore/db/StoragePoolDetailsDao.java        |    1 +
 .../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          |  174 +++++++-
 packaging/debian/init/cloud-management             |    2 +-
 packaging/debian/replace.properties                |    2 +-
 .../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 ++++++++++
 pom.xml                                            |   16 +
 .../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    |   29 +-
 .../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 +++-
 server/src/com/cloud/configuration/Config.java     |   54 ++-
 .../cloud/configuration/ConfigurationManager.java  |    2 +-
 .../configuration/ConfigurationManagerImpl.java    |   51 ++-
 .../cloud/configuration/dao/ConfigurationDao.java  |    1 +
 server/src/com/cloud/dc/dao/VlanDao.java           |    2 +
 server/src/com/cloud/dc/dao/VlanDaoImpl.java       |   19 +
 .../src/com/cloud/network/NetworkManagerImpl.java  |   20 +-
 .../src/com/cloud/network/NetworkServiceImpl.java  |   12 +-
 .../network/element/VirtualRouterElement.java      |    2 +-
 .../router/VirtualNetworkApplianceManagerImpl.java |    5 +-
 .../src/com/cloud/server/ConfigurationServer.java  |    5 +
 .../com/cloud/server/ConfigurationServerImpl.java  |   93 ++++-
 .../src/com/cloud/server/ManagementServerImpl.java |  308 +++++++++++--
 server/src/com/cloud/storage/VolumeManager.java    |    8 +
 .../src/com/cloud/storage/VolumeManagerImpl.java   |  112 +++++-
 .../storage/dao/StoragePoolDetailsDaoImpl.java     |    9 +
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  123 +++++
 server/src/com/cloud/vm/VirtualMachineManager.java |    4 +
 .../com/cloud/vm/VirtualMachineManagerImpl.java    |  233 +++++++++-
 .../test/com/cloud/vm/MockUserVmManagerImpl.java   |    8 +
 .../cloud/vm/MockVirtualMachineManagerImpl.java    |   10 +
 .../cloud/vm/VirtualMachineManagerImplTest.java    |  231 +++++++++-
 .../cloud/vpc/MockConfigurationManagerImpl.java    |    5 +-
 setup/db/db/schema-410to420.sql                    |    2 +
 test/integration/component/test_storage_motion.py  |  298 ++++++++++++
 test/integration/smoke/test_UpdateCfg.py           |   85 ++++
 .../definitions/systemvmtemplate/cleanup.sh        |    1 -
 .../definitions/systemvmtemplate64/cleanup.sh      |    1 -
 tools/build/build_asf.sh                           |    2 +-
 tools/marvin/marvin/integration/lib/oldbase.py     |   22 +
 ui/css/cloudstack3.css                             |   18 +-
 ui/index.jsp                                       |    5 +-
 ui/modules/modules.js                              |   20 +
 ui/scripts/instances.js                            |    2 +-
 ui/scripts/plugins.js                              |   95 +++--
 ui/scripts/ui-custom/pluginListing.js              |  109 +++++
 ui/scripts/ui-custom/plugins.js                    |  109 -----
 ui/scripts/zoneWizard.js                           |    2 +-
 100 files changed, 5177 insertions(+), 357 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4abd9292/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4abd9292/server/src/com/cloud/network/NetworkServiceImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4abd9292/server/src/com/cloud/storage/VolumeManagerImpl.java
----------------------------------------------------------------------


[34/35] Merge branch 'master' into marvin_refactor

Posted by ts...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4abd9292/tools/marvin/marvin/integration/lib/oldbase.py
----------------------------------------------------------------------
diff --cc tools/marvin/marvin/integration/lib/oldbase.py
index ca9feb4,0000000..c8aebe8
mode 100755,000000..100755
--- a/tools/marvin/marvin/integration/lib/oldbase.py
+++ b/tools/marvin/marvin/integration/lib/oldbase.py
@@@ -1,2536 -1,0 +1,2558 @@@
 +# 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.
 +
 +""" Base class for all Cloudstack resources
 +    -Virtual machine, Volume, Snapshot etc
 +"""
 +
 +import marvin
 +from utils import is_server_ssh_ready, random_gen
 +from marvin.cloudstackAPI import *
 +#Import System modules
 +import time
 +import hashlib
 +import base64
 +
 +
 +class Domain:
 +    """ Domain Life Cycle """
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, name=None, networkdomain=None,
 +               parentdomainid=None):
 +        """Creates an domain"""
 +
 +        cmd = createDomain.createDomainCmd()
 +
 +        if name:
 +            cmd.name = "-".join([name, random_gen()])
 +        elif "name" in services:
 +            cmd.name = "-".join([services["name"], random_gen()])
 +
 +        if networkdomain:
 +            cmd.networkdomain = networkdomain
 +        elif "networkdomain" in services:
 +            cmd.networkdomain = services["networkdomain"]
 +
 +        if parentdomainid:
 +            cmd.parentdomainid = parentdomainid
 +        elif "parentdomainid" in services:
 +            cmd.parentdomainid = services["parentdomainid"]
 +
 +        return Domain(apiclient.createDomain(cmd).__dict__)
 +
 +    def delete(self, apiclient, cleanup=None):
 +        """Delete an domain"""
 +        cmd = deleteDomain.deleteDomainCmd()
 +        cmd.id = self.id
 +        if cleanup:
 +            cmd.cleanup = cleanup
 +        apiclient.deleteDomain(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists domains"""
 +        cmd = listDomains.listDomainsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listDomains(cmd))
 +
 +
 +class Account:
 +    """ Account Life Cycle """
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, admin=False, domainid=None):
 +        """Creates an account"""
 +        cmd = createAccount.createAccountCmd()
 +
 +        #0 - User, 1 - Root Admin, 2 - Domain Admin
 +        cmd.accounttype = 2 if (admin and domainid) else int(admin)
 +
 +        cmd.email = services["email"]
 +        cmd.firstname = services["firstname"]
 +        cmd.lastname = services["lastname"]
 +
 +        cmd.password = services["password"]
 +        cmd.username = "-".join([services["username"], random_gen()])
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        account = apiclient.createAccount(cmd)
 +
 +        return Account(account.__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete an account"""
 +        cmd = deleteAccount.deleteAccountCmd()
 +        cmd.id = self.account.id
 +        apiclient.deleteAccount(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists accounts and provides detailed account information for
 +        listed accounts"""
 +
 +        cmd = listAccounts.listAccountsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listAccounts(cmd))
 +
 +
 +class User:
 +    """ User Life Cycle """
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, account, domainid):
 +        cmd = createUser.createUserCmd()
 +        """Creates an user"""
 +
 +        cmd.account = account
 +        cmd.domainid = domainid
 +        cmd.email = services["email"]
 +        cmd.firstname = services["firstname"]
 +        cmd.lastname = services["lastname"]
 +
 +        # Password Encoding
 +        mdf = hashlib.md5()
 +        mdf.update(services["password"])
 +        cmd.password = mdf.hexdigest()
 +        cmd.username = "-".join([services["username"], random_gen()])
 +        user = apiclient.createUser(cmd)
 +
 +        return User(user.__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete an account"""
 +        cmd = deleteUser.deleteUserCmd()
 +        cmd.id = self.id
 +        apiclient.deleteUser(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists users and provides detailed account information for
 +        listed users"""
 +
 +        cmd = listUsers.listUsersCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listUsers(cmd))
 +
 +    @classmethod
 +    def registerUserKeys(cls, apiclient, userid):
 +        cmd = registerUserKeys.registerUserKeysCmd()
 +        cmd.id = userid
 +        return apiclient.registerUserKeys(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Updates the user details"""
 +
 +        cmd = updateUser.updateUserCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return (apiclient.updateUser(cmd))
 +
 +    @classmethod
 +    def update(cls, apiclient, id, **kwargs):
 +        """Updates the user details (class method)"""
 +
 +        cmd = updateUser.updateUserCmd()
 +        cmd.id = id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return (apiclient.updateUser(cmd))
 +
 +    @classmethod
 +    def login(cls, apiclient, username, password, domain=None, domainid=None):
 +        """Logins to the CloudStack"""
 +
 +        cmd = login.loginCmd()
 +        cmd.username = username
 +        # MD5 hashcoded password
 +        mdf = hashlib.md5()
 +        mdf.update(password)
 +        cmd.password = mdf.hexdigest()
 +        if domain:
 +            cmd.domain = domain
 +        if domainid:
 +            cmd.domainid = domainid
 +        return apiclient.login(cmd)
 +
 +
 +class VirtualMachine:
 +    """Manage virtual machine lifecycle"""
 +
 +    def __init__(self, items, services):
 +        self.__dict__.update(items)
 +        if "username" in services:
 +            self.username = services["username"]
 +        else:
 +            self.username = 'root'
 +        if "password" in services:
 +            self.password = services["password"]
 +        else:
 +            self.password = 'password'
 +        if "ssh_port" in services:
 +            self.ssh_port = services["ssh_port"]
 +        else:
 +            self.ssh_port = 22
 +        self.ssh_client = None
 +        #extract out the ipaddress
 +        self.ipaddress = self.nic[0].ipaddress
 +
 +    @classmethod
 +    def create(cls, apiclient, services, templateid=None, accountid=None,
 +                    domainid=None, zoneid=None, networkids=None, serviceofferingid=None,
 +                    securitygroupids=None, projectid=None, startvm=None,
 +                    diskofferingid=None, affinitygroupnames=None, hostid=None, mode='basic'):
 +        """Create the instance"""
 +
 +        cmd = deployVirtualMachine.deployVirtualMachineCmd()
 +
 +        if serviceofferingid:
 +            cmd.serviceofferingid = serviceofferingid
 +        elif "serviceoffering" in services:
 +            cmd.serviceofferingid = services["serviceoffering"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        elif "zoneid" in services:
 +            cmd.zoneid = services["zoneid"]
 +        cmd.hypervisor = services["hypervisor"]
 +
 +        if accountid:
 +            cmd.account = accountid
 +        elif "account" in services:
 +            cmd.account = services["account"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        elif "domainid" in services:
 +            cmd.domainid = services["domainid"]
 +
 +        if networkids:
 +            cmd.networkids = networkids
 +        elif "networkids" in services:
 +            cmd.networkids = services["networkids"]
 +
 +        if templateid:
 +            cmd.templateid = templateid
 +        elif "template" in services:
 +            cmd.templateid = services["template"]
 +
 +        if "diskoffering" in services:
 +            cmd.diskofferingid = services["diskoffering"]
 +
 +        if securitygroupids:
 +            cmd.securitygroupids = [str(sg_id) for sg_id in securitygroupids]
 +
 +        if "userdata" in services:
 +            cmd.userdata = base64.b64encode(services["userdata"])
 +
 +        if "affinitygroupnames" in services:
 +            cmd.affinitygroupnames  = services["affinitygroupnames"]
 +        elif affinitygroupnames:
 +            cmd.affinitygroupnames  = affinitygroupnames
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        if startvm is not None:
 +            cmd.startvm = startvm
 +
 +        if hostid:
 +            cmd.hostid = hostid
 +
 +        virtual_machine = apiclient.deployVirtualMachine(cmd)
 +
 +        # VM should be in Running state after deploy
 +        timeout = 10
 +        while True:
 +            vm_status = VirtualMachine.list(
 +                                            apiclient,
 +                                            id=virtual_machine.id
 +                                            )
 +            if isinstance(vm_status, list):
 +                if vm_status[0].state == 'Running':
 +                    break
 +                elif timeout == 0:
 +                    raise Exception(
 +                            "TimeOutException: Failed to start VM (ID: %s)" %
 +                                                        virtual_machine.id)
 +
 +            time.sleep(10)
 +            timeout = timeout - 1
 +
 +        if mode.lower() == 'advanced':
 +            public_ip = PublicIPAddress.create(
 +                                           apiclient,
 +                                           virtual_machine.account,
 +                                           virtual_machine.zoneid,
 +                                           virtual_machine.domainid,
 +                                           services
 +                                           )
 +            fw_rule = FireWallRule.create(
 +                                          apiclient,
 +                                          ipaddressid=public_ip.ipaddress.id,
 +                                          protocol='TCP',
 +                                          cidrlist=['0.0.0.0/0'],
 +                                          startport=22,
 +                                          endport=22
 +                            )
 +            nat_rule = NATRule.create(
 +                                    apiclient,
 +                                    virtual_machine,
 +                                    services,
 +                                    ipaddressid=public_ip.ipaddress.id
 +                                    )
 +            virtual_machine.ssh_ip = nat_rule.ipaddress
 +            virtual_machine.public_ip = nat_rule.ipaddress
 +        else:
 +            virtual_machine.ssh_ip = virtual_machine.nic[0].ipaddress
 +            virtual_machine.public_ip = virtual_machine.nic[0].ipaddress
 +
 +        return VirtualMachine(virtual_machine.__dict__, services)
 +
 +    def start(self, apiclient):
 +        """Start the instance"""
 +        cmd = startVirtualMachine.startVirtualMachineCmd()
 +        cmd.id = self.id
 +        apiclient.startVirtualMachine(cmd)
 +
 +    def stop(self, apiclient):
 +        """Stop the instance"""
 +        cmd = stopVirtualMachine.stopVirtualMachineCmd()
 +        cmd.id = self.id
 +        apiclient.stopVirtualMachine(cmd)
 +
 +    def reboot(self, apiclient):
 +        """Reboot the instance"""
 +        cmd = rebootVirtualMachine.rebootVirtualMachineCmd()
 +        cmd.id = self.id
 +        apiclient.rebootVirtualMachine(cmd)
 +
 +    def get_ssh_client(self, ipaddress=None, reconnect=False, port=None):
 +        """Get SSH object of VM"""
 +
 +        # If NAT Rules are not created while VM deployment in Advanced mode
 +        # then, IP address must be passed
 +        if ipaddress != None:
 +            self.ssh_ip = ipaddress
 +        if port:
 +            self.ssh_port = port
 +
 +        if reconnect:
 +            self.ssh_client = is_server_ssh_ready(
 +                                                    self.ssh_ip,
 +                                                    self.ssh_port,
 +                                                    self.username,
 +                                                    self.password
 +                                                )
 +        self.ssh_client = self.ssh_client or is_server_ssh_ready(
 +                                                    self.ssh_ip,
 +                                                    self.ssh_port,
 +                                                    self.username,
 +                                                    self.password
 +                                                )
 +        return self.ssh_client
 +
 +    def delete(self, apiclient):
 +        """Destroy an Instance"""
 +        cmd = destroyVirtualMachine.destroyVirtualMachineCmd()
 +        cmd.id = self.id
 +        apiclient.destroyVirtualMachine(cmd)
 +
 +    def attach_volume(self, apiclient, volume):
 +        """Attach volume to instance"""
 +        cmd = attachVolume.attachVolumeCmd()
 +        cmd.id = volume.id
 +        cmd.virtualmachineid = self.id
 +        return apiclient.attachVolume(cmd)
 +
 +    def detach_volume(self, apiclient, volume):
 +        """Detach volume to instance"""
 +        cmd = detachVolume.detachVolumeCmd()
 +        cmd.id = volume.id
 +        return apiclient.detachVolume(cmd)
 +
 +    def add_nic(self, apiclient, networkId):
 +        """Add a NIC to a VM"""
 +        cmd = addNicToVirtualMachine.addNicToVirtualMachineCmd();
 +        cmd.virtualmachineid = self.id
 +        cmd.networkid = networkId
 +        return apiclient.addNicToVirtualMachine(cmd)
 +
 +    def remove_nic(self, apiclient, nicId):
 +        """Remove a NIC to a VM"""
 +        cmd = removeNicFromVirtualMachine.removeNicFromVirtualMachineCmd()
 +        cmd.nicid = nicId
 +        cmd.virtualmachineid = self.id
 +        return apiclient.removeNicFromVirtualMachine(cmd)
 +
 +    def update_default_nic(self, apiclient, nicId):
 +        """Set a NIC to be the default network adapter for a VM"""
 +        cmd = updateDefaultNicForVirtualMachine.updateDefaultNicForVirtualMachineCmd()
 +        cmd.nicid = nicId
 +        cmd.virtualmachineid = self.id
 +        return apiclient.updateDefaultNicForVirtualMachine(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all VMs matching criteria"""
 +
 +        cmd = listVirtualMachines.listVirtualMachinesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVirtualMachines(cmd))
 +
 +    def resetPassword(self, apiclient):
 +        """Resets VM password if VM created using password enabled template"""
 +
 +        cmd = resetPasswordForVirtualMachine.resetPasswordForVirtualMachineCmd()
 +        cmd.id = self.id
 +        try:
 +            response = apiclient.resetPasswordForVirtualMachine(cmd)
 +            print response
 +        except Exception as e:
 +            raise Exception("Reset Password failed! - %s" % e)
 +        print type(response)
 +        if isinstance(response, list):
 +            return response[0].password
 +
 +
 +class Volume:
 +    """Manage Volume Lifecycle
 +    """
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, zoneid=None, account=None,
 +               domainid=None, diskofferingid=None, projectid=None):
 +        """Create Volume"""
 +        cmd = createVolume.createVolumeCmd()
 +        cmd.name = services["diskname"]
 +
 +        if diskofferingid:
 +            cmd.diskofferingid = diskofferingid
 +        elif "diskofferingid" in services:
 +            cmd.diskofferingid = services["diskofferingid"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        elif "zoneid" in services:
 +            cmd.zoneid = services["zoneid"]
 +
 +        if account:
 +            cmd.account = account
 +        elif "account" in services:
 +            cmd.account = services["account"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        elif "domainid" in services:
 +            cmd.domainid = services["domainid"]
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +        return Volume(apiclient.createVolume(cmd).__dict__)
 +
 +    @classmethod
 +    def create_custom_disk(cls, apiclient, services, account=None,
 +                                    domainid=None, diskofferingid=None):
 +        """Create Volume from Custom disk offering"""
 +        cmd = createVolume.createVolumeCmd()
 +        cmd.name = services["diskname"]
 +
 +        if diskofferingid:
 +            cmd.diskofferingid = diskofferingid
 +        elif "customdiskofferingid" in services:
 +            cmd.diskofferingid = services["customdiskofferingid"]
 +
 +        cmd.size = services["customdisksize"]
 +        cmd.zoneid = services["zoneid"]
 +
 +        if account:
 +            cmd.account = account
 +        else:
 +            cmd.account = services["account"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        else:
 +            cmd.domainid = services["domainid"]
 +
 +        return Volume(apiclient.createVolume(cmd).__dict__)
 +
 +    @classmethod
 +    def create_from_snapshot(cls, apiclient, snapshot_id, services,
 +                             account=None, domainid=None):
 +        """Create Volume from snapshot"""
 +        cmd = createVolume.createVolumeCmd()
 +        cmd.name = "-".join([services["diskname"], random_gen()])
 +        cmd.snapshotid = snapshot_id
 +        cmd.zoneid = services["zoneid"]
 +        cmd.size = services["size"]
 +        if account:
 +            cmd.account = account
 +        else:
 +            cmd.account = services["account"]
 +        if domainid:
 +            cmd.domainid = domainid
 +        else:
 +            cmd.domainid = services["domainid"]
 +        return Volume(apiclient.createVolume(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Volume"""
 +        cmd = deleteVolume.deleteVolumeCmd()
 +        cmd.id = self.id
 +        apiclient.deleteVolume(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all volumes matching criteria"""
 +
 +        cmd = listVolumes.listVolumesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVolumes(cmd))
 +
 +    def resize(cls, apiclient, **kwargs):
 +        """Resize a volume"""
 +        cmd = resizeVolume.resizeVolumeCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.resizeVolume(cmd))
 +
++    @classmethod
++    def migrate(cls, apiclient, **kwargs):
++        """Migrate a volume"""
++        cmd = migrateVolume.migrateVolumeCmd()
++        [setattr(cmd, k, v) for k, v in kwargs.items()]
++        return(apiclient.migrateVolume(cmd))
++
 +class Snapshot:
 +    """Manage Snapshot Lifecycle
 +    """
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, volume_id, account=None,
 +                                            domainid=None, projectid=None):
 +        """Create Snapshot"""
 +        cmd = createSnapshot.createSnapshotCmd()
 +        cmd.volumeid = volume_id
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if projectid:
 +            cmd.projectid = projectid
 +        return Snapshot(apiclient.createSnapshot(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Snapshot"""
 +        cmd = deleteSnapshot.deleteSnapshotCmd()
 +        cmd.id = self.id
 +        apiclient.deleteSnapshot(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all snapshots matching criteria"""
 +
 +        cmd = listSnapshots.listSnapshotsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listSnapshots(cmd))
 +
 +
 +class Template:
 +    """Manage template life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, volumeid=None,
 +               account=None, domainid=None, projectid=None):
 +        """Create template from Volume"""
 +        #Create template from Virtual machine and Volume ID
 +        cmd = createTemplate.createTemplateCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        if "ostypeid" in services:
 +            cmd.ostypeid = services["ostypeid"]
 +        elif "ostype" in services:
 +            # Find OSTypeId from Os type
 +            sub_cmd = listOsTypes.listOsTypesCmd()
 +            sub_cmd.description = services["ostype"]
 +            ostypes = apiclient.listOsTypes(sub_cmd)
 +
 +            if not isinstance(ostypes, list):
 +                raise Exception(
 +                    "Unable to find Ostype id with desc: %s" %
 +                                                services["ostype"])
 +            cmd.ostypeid = ostypes[0].id
 +        else:
 +            raise Exception(
 +                    "Unable to find Ostype is required for creating template")
 +
 +        cmd.isfeatured = services["isfeatured"] if "isfeatured" in services else False
 +        cmd.ispublic = services["ispublic"] if "ispublic" in services else False
 +        cmd.isextractable = services["isextractable"] if "isextractable" in services else False
 +        cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False
 +        cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False
 +
 +        if volumeid:
 +            cmd.volumeid = volumeid
 +
 +        if account:
 +            cmd.account = account
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +        return Template(apiclient.createTemplate(cmd).__dict__)
 +
 +    @classmethod
 +    def register(cls, apiclient, services, zoneid=None,
 +                                                account=None, domainid=None):
 +        """Create template from URL"""
 +
 +        #Create template from Virtual machine and Volume ID
 +        cmd = registerTemplate.registerTemplateCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        cmd.format = services["format"]
 +        cmd.hypervisor = services["hypervisor"]
 +
 +        if "ostypeid" in services:
 +            cmd.ostypeid = services["ostypeid"]
 +        elif "ostype" in services:
 +            # Find OSTypeId from Os type
 +            sub_cmd = listOsTypes.listOsTypesCmd()
 +            sub_cmd.description = services["ostype"]
 +            ostypes = apiclient.listOsTypes(sub_cmd)
 +
 +            if not isinstance(ostypes, list):
 +                raise Exception(
 +                    "Unable to find Ostype id with desc: %s" %
 +                                                services["ostype"])
 +            cmd.ostypeid = ostypes[0].id
 +        else:
 +            raise Exception(
 +                    "Unable to find Ostype is required for registering template")
 +
 +        cmd.url = services["url"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        else:
 +            cmd.zoneid = services["zoneid"]
 +
 +        cmd.isfeatured = services["isfeatured"] if "isfeatured" in services else False
 +        cmd.ispublic = services["ispublic"] if "ispublic" in services else False
 +        cmd.isextractable = services["isextractable"] if "isextractable" in services else False
 +        cmd.passwordenabled = services["passwordenabled"] if "passwordenabled" in services else False
 +
 +        if account:
 +            cmd.account = account
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        # Register Template
 +        template = apiclient.registerTemplate(cmd)
 +
 +        if isinstance(template, list):
 +            return Template(template[0].__dict__)
 +
 +    @classmethod
 +    def create_from_snapshot(cls, apiclient, snapshot, services,
 +                                                        random_name=True):
 +        """Create Template from snapshot"""
 +        #Create template from Virtual machine and Snapshot ID
 +        cmd = createTemplate.createTemplateCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = "-".join([
 +                             services["name"],
 +                             random_gen()
 +                            ]) if random_name else services["name"]
 +
 +        if "ostypeid" in services:
 +            cmd.ostypeid = services["ostypeid"]
 +        elif "ostype" in services:
 +            # Find OSTypeId from Os type
 +            sub_cmd = listOsTypes.listOsTypesCmd()
 +            sub_cmd.description = services["ostype"]
 +            ostypes = apiclient.listOsTypes(sub_cmd)
 +
 +            if not isinstance(ostypes, list):
 +                raise Exception(
 +                    "Unable to find Ostype id with desc: %s" %
 +                                                services["ostype"])
 +            cmd.ostypeid = ostypes[0].id
 +        else:
 +            raise Exception(
 +                    "Unable to find Ostype is required for creating template")
 +
 +        cmd.snapshotid = snapshot.id
 +        return Template(apiclient.createTemplate(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Template"""
 +
 +        cmd = deleteTemplate.deleteTemplateCmd()
 +        cmd.id = self.id
 +        apiclient.deleteTemplate(cmd)
 +
 +    def download(self, apiclient, timeout=5, interval=60):
 +        """Download Template"""
 +        #Sleep to ensure template is in proper state before download
 +        time.sleep(interval)
 +
 +        while True:
 +            template_response = Template.list(
 +                                    apiclient,
 +                                    id=self.id,
 +                                    zoneid=self.zoneid,
 +                                    templatefilter='self'
 +                                    )
 +            if isinstance(template_response, list):
 +
 +                template = template_response[0]
 +                # If template is ready,
 +                # template.status = Download Complete
 +                # Downloading - x% Downloaded
 +                # Error - Any other string
 +                if template.status == 'Download Complete':
 +                    break
 +
 +                elif 'Downloaded' in template.status:
 +                    time.sleep(interval)
 +
 +                elif 'Installing' not in template.status:
 +                    raise Exception(
 +                        "Error in downloading template: status - %s" %
 +                                                            template.status)
 +
 +            elif timeout == 0:
 +                break
 +
 +            else:
 +                time.sleep(interval)
 +                timeout = timeout - 1
 +        return
 +
 +    def updatePermissions(self, apiclient, **kwargs):
 +        """Updates the template permissions"""
 +
 +        cmd = updateTemplatePermissions.updateTemplatePermissionsCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.updateTemplatePermissions(cmd))
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all templates matching criteria"""
 +
 +        cmd = listTemplates.listTemplatesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listTemplates(cmd))
 +
 +
 +class Iso:
 +    """Manage ISO life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, account=None, domainid=None,
 +                                                        projectid=None):
 +        """Create an ISO"""
 +        #Create ISO from URL
 +        cmd = registerIso.registerIsoCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = services["name"]
 +        if "ostypeid" in services:
 +            cmd.ostypeid = services["ostypeid"]
 +        elif "ostype" in services:
 +            # Find OSTypeId from Os type
 +            sub_cmd = listOsTypes.listOsTypesCmd()
 +            sub_cmd.description = services["ostype"]
 +            ostypes = apiclient.listOsTypes(sub_cmd)
 +
 +            if not isinstance(ostypes, list):
 +                raise Exception(
 +                    "Unable to find Ostype id with desc: %s" %
 +                                                services["ostype"])
 +            cmd.ostypeid = ostypes[0].id
 +        else:
 +            raise Exception(
 +                    "Unable to find Ostype is required for creating ISO")
 +
 +        cmd.url = services["url"]
 +        cmd.zoneid = services["zoneid"]
 +
 +        if "isextractable" in services:
 +            cmd.isextractable = services["isextractable"]
 +        if "isfeatured" in services:
 +            cmd.isfeatured = services["isfeatured"]
 +        if "ispublic" in services:
 +            cmd.ispublic = services["ispublic"]
 +
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if projectid:
 +            cmd.projectid = projectid
 +        # Register ISO
 +        iso = apiclient.registerIso(cmd)
 +
 +        if iso:
 +            return Iso(iso[0].__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete an ISO"""
 +        cmd = deleteIso.deleteIsoCmd()
 +        cmd.id = self.id
 +        apiclient.deleteIso(cmd)
 +        return
 +
 +    def download(self, apiclient, timeout=5, interval=60):
 +        """Download an ISO"""
 +        #Ensuring ISO is successfully downloaded
 +        while True:
 +            time.sleep(interval)
 +
 +            cmd = listIsos.listIsosCmd()
 +            cmd.id = self.id
 +            iso_response = apiclient.listIsos(cmd)
 +
 +            if isinstance(iso_response, list):
 +                response = iso_response[0]
 +                # Again initialize timeout to avoid listISO failure
 +                timeout = 5
 +                print response.status
 +                # Check whether download is in progress(for Ex:10% Downloaded)
 +                # or ISO is 'Successfully Installed'
 +                if response.status == 'Successfully Installed':
 +                    return
 +                elif 'Downloaded' not in response.status and \
 +                    'Installing' not in response.status:
 +                    raise Exception(
 +                        "Error In Downloading ISO: ISO Status - %s" %
 +                                                            response.status)
 +
 +            elif timeout == 0:
 +                raise Exception("ISO download Timeout Exception")
 +            else:
 +                timeout = timeout - 1
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all available ISO files."""
 +
 +        cmd = listIsos.listIsosCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listIsos(cmd))
 +
 +
 +class PublicIPAddress:
 +    """Manage Public IP Addresses"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, accountid=None, zoneid=None, domainid=None,
 +               services=None, networkid=None, projectid=None, vpcid=None):
 +        """Associate Public IP address"""
 +        cmd = associateIpAddress.associateIpAddressCmd()
 +
 +        if accountid:
 +            cmd.account = accountid
 +        elif "account" in services:
 +            cmd.account = services["account"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        elif "zoneid" in services:
 +            cmd.zoneid = services["zoneid"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        elif "domainid" in services:
 +            cmd.domainid = services["domainid"]
 +
 +        if networkid:
 +            cmd.networkid = networkid
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        if vpcid:
 +            cmd.vpcid = vpcid
 +        return PublicIPAddress(apiclient.associateIpAddress(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Dissociate Public IP address"""
 +        cmd = disassociateIpAddress.disassociateIpAddressCmd()
 +        cmd.id = self.ipaddress.id
 +        apiclient.disassociateIpAddress(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Public IPs matching criteria"""
 +
 +        cmd = listPublicIpAddresses.listPublicIpAddressesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listPublicIpAddresses(cmd))
 +
 +
 +class NATRule:
 +    """Manage port forwarding rule"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, virtual_machine, services, ipaddressid=None,
 +                                                            projectid=None, networkid=None):
 +        """Create Port forwarding rule"""
 +        cmd = createPortForwardingRule.createPortForwardingRuleCmd()
 +
 +        if ipaddressid:
 +            cmd.ipaddressid = ipaddressid
 +        elif "ipaddressid" in services:
 +            cmd.ipaddressid = services["ipaddressid"]
 +
 +        cmd.privateport = services["privateport"]
 +        cmd.publicport = services["publicport"]
 +        cmd.protocol = services["protocol"]
 +        cmd.virtualmachineid = virtual_machine.id
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        if networkid:
 +            cmd.networkid = networkid
 +
 +        return NATRule(apiclient.createPortForwardingRule(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete port forwarding"""
 +        cmd = deletePortForwardingRule.deletePortForwardingRuleCmd()
 +        cmd.id = self.id
 +        apiclient.deletePortForwardingRule(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all NAT rules matching criteria"""
 +
 +        cmd = listPortForwardingRules.listPortForwardingRulesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listPortForwardingRules(cmd))
 +
 +
 +class StaticNATRule:
 +    """Manage Static NAT rule"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, ipaddressid=None, vpcid=None):
 +        """Creates static ip forwarding rule"""
 +
 +        cmd = createIpForwardingRule.createIpForwardingRuleCmd()
 +        cmd.protocol = services["protocol"]
 +        cmd.startport = services["startport"]
 +
 +        if "endport" in services:
 +            cmd.endport = services["endport"]
 +
 +        if "cidrlist" in services:
 +            cmd.cidrlist = services["cidrlist"]
 +
 +        if ipaddressid:
 +            cmd.ipaddressid = ipaddressid
 +        elif "ipaddressid" in services:
 +            cmd.ipaddressid = services["ipaddressid"]
 +
 +        if vpcid:
 +            cmd.vpcid = vpcid
 +
 +        return StaticNATRule(apiclient.createIpForwardingRule(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete IP forwarding rule"""
 +        cmd = deleteIpForwardingRule.deleteIpForwardingRuleCmd()
 +        cmd.id = self.id
 +        apiclient.deleteIpForwardingRule(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all IP forwarding rules matching criteria"""
 +
 +        cmd = listIpForwardingRules.listIpForwardingRulesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listIpForwardingRules(cmd))
 +
 +    @classmethod
 +    def enable(cls, apiclient, ipaddressid, virtualmachineid):
 +        """Enables Static NAT rule"""
 +
 +        cmd = enableStaticNat.enableStaticNatCmd()
 +        cmd.ipaddressid = ipaddressid
 +        cmd.virtualmachineid = virtualmachineid
 +        apiclient.enableStaticNat(cmd)
 +        return
 +
 +    @classmethod
 +    def disable(cls, apiclient, ipaddressid, virtualmachineid):
 +        """Disables Static NAT rule"""
 +
 +        cmd = disableStaticNat.disableStaticNatCmd()
 +        cmd.ipaddressid = ipaddressid
 +        apiclient.disableStaticNat(cmd)
 +        return
 +
 +
 +class FireWallRule:
 +    """Manage Firewall rule"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, ipaddressid, protocol, cidrlist=None,
 +               startport=None, endport=None, projectid=None, vpcid=None):
 +        """Create Firewall Rule"""
 +        cmd = createFirewallRule.createFirewallRuleCmd()
 +        cmd.ipaddressid = ipaddressid
 +        cmd.protocol = protocol
 +        if cidrlist:
 +            cmd.cidrlist = cidrlist
 +        if startport:
 +            cmd.startport = startport
 +        if endport:
 +            cmd.endport = endport
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        if vpcid:
 +            cmd.vpcid = vpcid
 +
 +        return FireWallRule(apiclient.createFirewallRule(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Firewall rule"""
 +        cmd = deleteFirewallRule.deleteFirewallRuleCmd()
 +        cmd.id = self.id
 +        apiclient.deleteFirewallRule(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Firewall Rules matching criteria"""
 +
 +        cmd = listFirewallRules.listFirewallRulesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listFirewallRules(cmd))
 +
 +
 +class ServiceOffering:
 +    """Manage service offerings cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, domainid=None, **kwargs):
 +        """Create Service offering"""
 +        cmd = createServiceOffering.createServiceOfferingCmd()
 +        cmd.cpunumber = services["cpunumber"]
 +        cmd.cpuspeed = services["cpuspeed"]
 +        cmd.displaytext = services["displaytext"]
 +        cmd.memory = services["memory"]
 +        cmd.name = services["name"]
 +        if "storagetype" in services:
 +            cmd.storagetype = services["storagetype"]
 +
 +        # Service Offering private to that domain
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return ServiceOffering(apiclient.createServiceOffering(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Service offering"""
 +        cmd = deleteServiceOffering.deleteServiceOfferingCmd()
 +        cmd.id = self.id
 +        apiclient.deleteServiceOffering(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all available service offerings."""
 +
 +        cmd = listServiceOfferings.listServiceOfferingsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listServiceOfferings(cmd))
 +
 +
 +class DiskOffering:
 +    """Manage disk offerings cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, custom=False, domainid=None):
 +        """Create Disk offering"""
 +        cmd = createDiskOffering.createDiskOfferingCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = services["name"]
 +        if custom:
 +            cmd.customized = True
 +        else:
 +            cmd.disksize = services["disksize"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        if "storagetype" in services:
 +            cmd.storagetype = services["storagetype"]
 +
 +        return DiskOffering(apiclient.createDiskOffering(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Disk offering"""
 +        cmd = deleteDiskOffering.deleteDiskOfferingCmd()
 +        cmd.id = self.id
 +        apiclient.deleteDiskOffering(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all available disk offerings."""
 +
 +        cmd = listDiskOfferings.listDiskOfferingsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listDiskOfferings(cmd))
 +
 +
 +class NetworkOffering:
 +    """Manage network offerings cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, **kwargs):
 +        """Create network offering"""
 +
 +        cmd = createNetworkOffering.createNetworkOfferingCmd()
 +        cmd.displaytext = "-".join([services["displaytext"], random_gen()])
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        cmd.guestiptype = services["guestiptype"]
 +        cmd.supportedservices = services["supportedservices"]
 +        cmd.traffictype = services["traffictype"]
 +
 +        cmd.serviceProviderList = []
 +        for service, provider in services["serviceProviderList"].items():
 +            cmd.serviceProviderList.append({
 +                                            'service': service,
 +                                            'provider': provider
 +                                           })
 +        if "servicecapabilitylist" in services:
 +            cmd.servicecapabilitylist = []
 +            for service, capability in services["servicecapabilitylist"].items():
 +                for ctype, value in capability.items():
 +                    cmd.servicecapabilitylist.append({
 +                                            'service': service,
 +                                            'capabilitytype': ctype,
 +                                            'capabilityvalue': value
 +                                           })
 +        if "specifyVlan" in services:
 +            cmd.specifyVlan = services["specifyVlan"]
 +        if "specifyIpRanges" in services:
 +            cmd.specifyIpRanges = services["specifyIpRanges"]
 +
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +
 +        return NetworkOffering(apiclient.createNetworkOffering(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete network offering"""
 +        cmd = deleteNetworkOffering.deleteNetworkOfferingCmd()
 +        cmd.id = self.id
 +        apiclient.deleteNetworkOffering(cmd)
 +        return
 +
 +    def update(self, apiclient, **kwargs):
 +        """Lists all available network offerings."""
 +
 +        cmd = updateNetworkOffering.updateNetworkOfferingCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.updateNetworkOffering(cmd))
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all available network offerings."""
 +
 +        cmd = listNetworkOfferings.listNetworkOfferingsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listNetworkOfferings(cmd))
 +
 +
 +class SnapshotPolicy:
 +    """Manage snapshot policies"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, volumeid, services):
 +        """Create Snapshot policy"""
 +        cmd = createSnapshotPolicy.createSnapshotPolicyCmd()
 +        cmd.intervaltype = services["intervaltype"]
 +        cmd.maxsnaps = services["maxsnaps"]
 +        cmd.schedule = services["schedule"]
 +        cmd.timezone = services["timezone"]
 +        cmd.volumeid = volumeid
 +        return SnapshotPolicy(apiclient.createSnapshotPolicy(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Snapshot policy"""
 +        cmd = deleteSnapshotPolicies.deleteSnapshotPoliciesCmd()
 +        cmd.id = self.id
 +        apiclient.deleteSnapshotPolicies(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists snapshot policies."""
 +
 +        cmd = listSnapshotPolicies.listSnapshotPoliciesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listSnapshotPolicies(cmd))
 +
 +
 +class LoadBalancerRule:
 +    """Manage Load Balancer rule"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, ipaddressid=None, accountid=None,
 +                            networkid=None, projectid=None, domainid=None):
 +        """Create Load balancing Rule"""
 +
 +        cmd = createLoadBalancerRule.createLoadBalancerRuleCmd()
 +
 +        if ipaddressid:
 +            cmd.publicipid = ipaddressid
 +        elif "ipaddressid" in services:
 +            cmd.publicipid = services["ipaddressid"]
 +
 +        if accountid:
 +            cmd.account = accountid
 +        elif "account" in services:
 +            cmd.account = services["account"]
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        cmd.name = services["name"]
 +        cmd.algorithm = services["alg"]
 +        cmd.privateport = services["privateport"]
 +        cmd.publicport = services["publicport"]
 +
 +        if "openfirewall" in services:
 +            cmd.openfirewall = services["openfirewall"]
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        if networkid:
 +            cmd.networkid = networkid
 +        return LoadBalancerRule(apiclient.createLoadBalancerRule(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete load balancing rule"""
 +        cmd = deleteLoadBalancerRule.deleteLoadBalancerRuleCmd()
 +        cmd.id = self.id
 +        apiclient.deleteLoadBalancerRule(cmd)
 +        return
 +
 +    def assign(self, apiclient, vms):
 +        """Assign virtual machines to load balancing rule"""
 +        cmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd()
 +        cmd.id = self.id
 +        cmd.virtualmachineids = [str(vm.id) for vm in vms]
 +        apiclient.assignToLoadBalancerRule(cmd)
 +        return
 +
 +    def remove(self, apiclient, vms):
 +        """Remove virtual machines from load balancing rule"""
 +        cmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd()
 +        cmd.id = self.id
 +        cmd.virtualmachineids = [str(vm.id) for vm in vms]
 +        apiclient.removeFromLoadBalancerRule(cmd)
 +        return
 +
 +    def update(self, apiclient, algorithm=None, description=None, name=None, **kwargs):
 +        """Updates the load balancing rule"""
 +        cmd = updateLoadBalancerRule.updateLoadBalancerRuleCmd()
 +        cmd.id = self.id
 +        if algorithm:
 +            cmd.algorithm = algorithm
 +        if description:
 +            cmd.description = description
 +        if name:
 +            cmd.name = name
 +
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updateLoadBalancerRule(cmd)
 +
 +    def createSticky(self, apiclient, methodname, name, description=None, param=None):
 +        """Creates a sticky policy for the LB rule"""
 +
 +        cmd = createLBStickinessPolicy.createLBStickinessPolicyCmd()
 +        cmd.lbruleid = self.id
 +        cmd.methodname = methodname
 +        cmd.name = name
 +        if description:
 +            cmd.description = description
 +        if param:
 +            cmd.param = []
 +            for name, value in param.items():
 +                cmd.param.append({'name': name, 'value': value})
 +        return apiclient.createLBStickinessPolicy(cmd)
 +
 +    def deleteSticky(self, apiclient, id):
 +        """Deletes stickyness policy"""
 +
 +        cmd = deleteLBStickinessPolicy.deleteLBStickinessPolicyCmd()
 +        cmd.id = id
 +        return apiclient.deleteLBStickinessPolicy(cmd)
 +
 +    @classmethod
 +    def listStickyPolicies(cls, apiclient, lbruleid, **kwargs):
 +        """Lists stickiness policies for load balancing rule"""
 +
 +        cmd= listLBStickinessPolicies.listLBStickinessPoliciesCmd()
 +        cmd.lbruleid = lbruleid
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.listLBStickinessPolicies(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Load balancing rules matching criteria"""
 +
 +        cmd = listLoadBalancerRules.listLoadBalancerRulesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listLoadBalancerRules(cmd))
 +
 +
 +class Cluster:
 +    """Manage Cluster life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, zoneid=None, podid=None):
 +        """Create Cluster"""
 +        cmd = addCluster.addClusterCmd()
 +        cmd.clustertype = services["clustertype"]
 +        cmd.hypervisor = services["hypervisor"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        else:
 +            cmd.zoneid = services["zoneid"]
 +
 +        if podid:
 +            cmd.podid = podid
 +        else:
 +            cmd.podid = services["podid"]
 +
 +        if "username" in services:
 +            cmd.username = services["username"]
 +        if "password" in services:
 +            cmd.password = services["password"]
 +        if "url" in services:
 +            cmd.url = services["url"]
 +        if "clustername" in services:
 +            cmd.clustername = services["clustername"]
 +
 +        return Cluster(apiclient.addCluster(cmd)[0].__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Cluster"""
 +        cmd = deleteCluster.deleteClusterCmd()
 +        cmd.id = self.id
 +        apiclient.deleteCluster(cmd)
 +        return
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Clusters matching criteria"""
 +
 +        cmd = listClusters.listClustersCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listClusters(cmd))
 +
 +
 +class Host:
 +    """Manage Host life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, cluster, services, zoneid=None, podid=None):
 +        """Create Host in cluster"""
 +
 +        cmd = addHost.addHostCmd()
 +        cmd.hypervisor = services["hypervisor"]
 +        cmd.url = services["url"]
 +        cmd.clusterid = cluster.id
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        else:
 +            cmd.zoneid = services["zoneid"]
 +
 +        if podid:
 +            cmd.podid = podid
 +        else:
 +            cmd.podid = services["podid"]
 +
 +        if "clustertype" in services:
 +            cmd.clustertype = services["clustertype"]
 +        if "username" in services:
 +            cmd.username = services["username"]
 +        if "password" in services:
 +            cmd.password = services["password"]
 +
 +        # Add host
 +        host = apiclient.addHost(cmd)
 +
 +        if isinstance(host, list):
 +            return Host(host[0].__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Host"""
 +        # Host must be in maintenance mode before deletion
 +        cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
 +        cmd.id = self.id
 +        apiclient.prepareHostForMaintenance(cmd)
 +        time.sleep(30)
 +
 +        cmd = deleteHost.deleteHostCmd()
 +        cmd.id = self.id
 +        apiclient.deleteHost(cmd)
 +        return
 +
 +    def enableMaintenance(self, apiclient):
 +        """enables maintainance mode Host"""
 +
 +        cmd = prepareHostForMaintenance.prepareHostForMaintenanceCmd()
 +        cmd.id = self.id
 +        return apiclient.prepareHostForMaintenance(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Hosts matching criteria"""
 +
 +        cmd = listHosts.listHostsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listHosts(cmd))
 +
++    @classmethod
++    def listForMigration(cls, apiclient, **kwargs):
++        """List all Hosts for migration matching criteria"""
++
++        cmd = findHostsForMigration.findHostsForMigrationCmd()
++        [setattr(cmd, k, v) for k, v in kwargs.items()]
++        return(apiclient.findHostsForMigration(cmd))
++
 +
 +class StoragePool:
 +    """Manage Storage pools (Primary Storage)"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, clusterid=None,
 +                                        zoneid=None, podid=None):
 +        """Create Storage pool (Primary Storage)"""
 +
 +        cmd = createStoragePool.createStoragePoolCmd()
 +        cmd.name = services["name"]
 +
 +        if podid:
 +            cmd.podid = podid
 +        else:
 +            cmd.podid = services["podid"]
 +
 +        cmd.url = services["url"]
 +        if clusterid:
 +            cmd.clusterid = clusterid
 +        elif "clusterid" in services:
 +            cmd.clusterid = services["clusterid"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        else:
 +            cmd.zoneid = services["zoneid"]
 +
 +        return StoragePool(apiclient.createStoragePool(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Storage pool (Primary Storage)"""
 +
 +        # Storage pool must be in maintenance mode before deletion
 +        cmd = enableStorageMaintenance.enableStorageMaintenanceCmd()
 +        cmd.id = self.id
 +        apiclient.enableStorageMaintenance(cmd)
 +        time.sleep(30)
 +        cmd = deleteStoragePool.deleteStoragePoolCmd()
 +        cmd.id = self.id
 +        apiclient.deleteStoragePool(cmd)
 +        return
 +
 +    def enableMaintenance(self, apiclient):
 +        """enables maintainance mode Storage pool"""
 +
 +        cmd = enableStorageMaintenance.enableStorageMaintenanceCmd()
 +        cmd.id = self.id
 +        return apiclient.enableStorageMaintenance(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all storage pools matching criteria"""
 +
 +        cmd = listStoragePools.listStoragePoolsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listStoragePools(cmd))
 +
++    @classmethod
++    def listForMigration(cls, apiclient, **kwargs):
++        """List all storage pools for migration matching criteria"""
++
++        cmd = findStoragePoolsForMigration.findStoragePoolsForMigrationCmd()
++        [setattr(cmd, k, v) for k, v in kwargs.items()]
++        return(apiclient.findStoragePoolsForMigration(cmd))
 +
 +class Network:
 +    """Manage Network pools"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, accountid=None, domainid=None,
 +               networkofferingid=None, projectid=None, zoneid=None,
 +               gateway=None, netmask=None, vpcid=None, guestcidr=None):
 +        """Create Network for account"""
 +        cmd = createNetwork.createNetworkCmd()
 +        cmd.name = services["name"]
 +        cmd.displaytext = services["displaytext"]
 +
 +        if networkofferingid:
 +            cmd.networkofferingid = networkofferingid
 +        elif "networkoffering" in services:
 +            cmd.networkofferingid = services["networkoffering"]
 +
 +        if zoneid:
 +            cmd.zoneid = zoneid
 +        elif "zoneid" in services:
 +            cmd.zoneid = services["zoneid"]
 +
 +        if gateway:
 +            cmd.gateway = gateway
 +        elif "gateway" in services:
 +            cmd.gateway = services["gateway"]
 +        if netmask:
 +            cmd.netmask = netmask
 +        elif "netmask" in services:
 +            cmd.netmask = services["netmask"]
 +        if "startip" in services:
 +            cmd.startip = services["startip"]
 +        if "endip" in services:
 +            cmd.endip = services["endip"]
 +        if "vlan" in services:
 +            cmd.vlan = services["vlan"]
 +        if "acltype" in services:
 +            cmd.acltype = services["acltype"]
 +
 +        if accountid:
 +            cmd.account = accountid
 +        if domainid:
 +            cmd.domainid = domainid
 +        if projectid:
 +            cmd.projectid = projectid
 +        if guestcidr:
 +            cmd.guestcidr = guestcidr
 +        if vpcid:
 +            cmd.vpcid = vpcid
 +        return Network(apiclient.createNetwork(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Account"""
 +
 +        cmd = deleteNetwork.deleteNetworkCmd()
 +        cmd.id = self.id
 +        apiclient.deleteNetwork(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Updates network with parameters passed"""
 +
 +        cmd = updateNetwork.updateNetworkCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.updateNetwork(cmd))
 +
 +    def restart(self, apiclient, cleanup=None):
 +        """Restarts the network"""
 +
 +        cmd = restartNetwork.restartNetworkCmd()
 +        cmd.id = self.id
 +        if cleanup:
 +            cmd.cleanup = cleanup
 +        return(apiclient.restartNetwork(cmd))
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Networks matching criteria"""
 +
 +        cmd = listNetworks.listNetworksCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listNetworks(cmd))
 +
 +
 +class NetworkACL:
 +    """Manage Network ACL lifecycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, networkid, services, traffictype=None):
 +        """Create network ACL rules(Ingress/Egress)"""
 +
 +        cmd = createNetworkACL.createNetworkACLCmd()
 +        cmd.networkid = networkid
 +        if "protocol" in services:
 +            cmd.protocol = services["protocol"]
 +
 +        if services["protocol"] == 'ICMP':
 +            cmd.icmptype = -1
 +            cmd.icmpcode = -1
 +        else:
 +            cmd.startport = services["startport"]
 +            cmd.endport = services["endport"]
 +
 +        cmd.cidrlist = services["cidrlist"]
 +        if traffictype:
 +            cmd.traffictype = traffictype
 +            # Defaulted to Ingress
 +        return NetworkACL(apiclient.createNetworkACL(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete network acl"""
 +
 +        cmd = deleteNetworkACL.deleteNetworkACLCmd()
 +        cmd.id = self.id
 +        return apiclient.deleteNetworkACL(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List Network ACLs"""
 +
 +        cmd = listNetworkACLs.listNetworkACLsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listNetworkACLs(cmd))
 +
 +
 +class Vpn:
 +    """Manage VPN life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, publicipid, account=None, domainid=None,
 +                                                            projectid=None, vpcid=None):
 +        """Create VPN for Public IP address"""
 +        cmd = createRemoteAccessVpn.createRemoteAccessVpnCmd()
 +        cmd.publicipid = publicipid
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if projectid:
 +            cmd.projectid = projectid
 +        if vpcid:
 +            cmd.vpcid = vpcid
 +        return Vpn(apiclient.createRemoteAccessVpn(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete remote VPN access"""
 +
 +        cmd = deleteRemoteAccessVpn.deleteRemoteAccessVpnCmd()
 +        cmd.publicipid = self.publicipid
 +        apiclient.deleteRemoteAccessVpn(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all VPN matching criteria"""
 +
 +        cmd = listRemoteAccessVpns.listRemoteAccessVpnsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listRemoteAccessVpns(cmd))
 +
 +
 +class VpnUser:
 +    """Manage VPN user"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, username, password, account=None, domainid=None,
 +               projectid=None):
 +        """Create VPN user"""
 +        cmd = addVpnUser.addVpnUserCmd()
 +        cmd.username = username
 +        cmd.password = password
 +
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if projectid:
 +            cmd.projectid = projectid
 +        return VpnUser(apiclient.addVpnUser(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Remove VPN user"""
 +
 +        cmd = removeVpnUser.removeVpnUserCmd()
 +        cmd.username = self.username
 +        cmd.account = self.account
 +        cmd.domainid = self.domainid
 +        apiclient.removeVpnUser(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all VPN Users matching criteria"""
 +
 +        cmd = listVpnUsers.listVpnUsersCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVpnUsers(cmd))
 +
 +
 +class Zone:
 +    """Manage Zone"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, domainid=None):
 +        """Create zone"""
 +        cmd = createZone.createZoneCmd()
 +        cmd.dns1 = services["dns1"]
 +        cmd.internaldns1 = services["internaldns1"]
 +        cmd.name = services["name"]
 +        cmd.networktype = services["networktype"]
 +
 +        if "dns2" in services:
 +            cmd.dns2 = services["dns2"]
 +        if "internaldns2" in services:
 +            cmd.internaldns2 = services["internaldns2"]
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        return Zone(apiclient.createZone(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Zone"""
 +
 +        cmd = deleteZone.deleteZoneCmd()
 +        cmd.id = self.id
 +        apiclient.deleteZone(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Update the zone"""
 +
 +        cmd = updateZone.updateZoneCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updateZone(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List all Zones matching criteria"""
 +
 +        cmd = listZones.listZonesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listZones(cmd))
 +
 +
 +class Pod:
 +    """Manage Pod"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services):
 +        """Create Pod"""
 +        cmd = createPod.createPodCmd()
 +        cmd.gateway = services["gateway"]
 +        cmd.netmask = services["netmask"]
 +        cmd.name = services["name"]
 +        cmd.startip = services["startip"]
 +        cmd.endip = services["endip"]
 +        cmd.zoneid = services["zoneid"]
 +
 +        return Pod(apiclient.createPod(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Pod"""
 +
 +        cmd = deletePod.deletePodCmd()
 +        cmd.id = self.id
 +        apiclient.deletePod(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        "Returns a default pod for specified zone"
 +
 +        cmd = listPods.listPodsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.listPods(cmd)
 +
 +
 +class PublicIpRange:
 +    """Manage VlanIpRange"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services):
 +        """Create VlanIpRange"""
 +
 +        cmd = createVlanIpRange.createVlanIpRangeCmd()
 +        cmd.gateway = services["gateway"]
 +        cmd.netmask = services["netmask"]
 +        cmd.forvirtualnetwork = services["forvirtualnetwork"]
 +        cmd.startip = services["startip"]
 +        cmd.endip = services["endip"]
 +        cmd.zoneid = services["zoneid"]
 +        cmd.podid = services["podid"]
 +        cmd.vlan = services["vlan"]
 +
 +        return PublicIpRange(apiclient.createVlanIpRange(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete VlanIpRange"""
 +
 +        cmd = deleteVlanIpRange.deleteVlanIpRangeCmd()
 +        cmd.id = self.vlan.id
 +        apiclient.deleteVlanIpRange(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all VLAN IP ranges."""
 +
 +        cmd = listVlanIpRanges.listVlanIpRangesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVlanIpRanges(cmd))
 +
 +    @classmethod
 +    def dedicate(cls, apiclient, id, account=None, domainid=None, projectid=None):
 +        """Dedicate VLAN IP range"""
 +
 +        cmd = dedicatePublicIpRange.dedicatePublicIpRangeCmd()
 +        cmd.id = id
 +        cmd.account = account
 +        cmd.domainid = domainid
 +        cmd.projectid = projectid
 +        return PublicIpRange(apiclient.dedicatePublicIpRange(cmd).__dict__)
 +
 +    def release(self, apiclient):
 +        """Release VLAN IP range"""
 +
 +        cmd = releasePublicIpRange.releasePublicIpRangeCmd()
 +        cmd.id = self.vlan.id
 +        return apiclient.releasePublicIpRange(cmd)
 +
 +class SecondaryStorage:
 +    """Manage Secondary storage"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services):
 +        """Create Secondary Storage"""
 +        cmd = addSecondaryStorage.addSecondaryStorageCmd()
 +
 +        cmd.url = services["url"]
 +        if "zoneid" in services:
 +            cmd.zoneid = services["zoneid"]
 +        return SecondaryStorage(apiclient.addSecondaryStorage(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Secondary Storage"""
 +
 +        cmd = deleteHost.deleteHostCmd()
 +        cmd.id = self.id
 +        apiclient.deleteHost(cmd)
 +
 +
 +class PhysicalNetwork:
 +    """Manage physical network storage"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, zoneid, domainid=None):
 +        """Create physical network"""
 +        cmd = createPhysicalNetwork.createPhysicalNetworkCmd()
 +
 +        cmd.name = services["name"]
 +        cmd.zoneid = zoneid
 +        if domainid:
 +            cmd.domainid = domainid
 +        return PhysicalNetwork(apiclient.createPhysicalNetwork(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Physical Network"""
 +
 +        cmd = deletePhysicalNetwork.deletePhysicalNetworkCmd()
 +        cmd.id = self.id
 +        apiclient.deletePhysicalNetwork(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Update Physical network state"""
 +
 +        cmd = updatePhysicalNetwork.updatePhysicalNetworkCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updatePhysicalNetwork(cmd)
 +
 +    def addTrafficType(self, apiclient, type):
 +        """Add Traffic type to Physical network"""
 +
 +        cmd = addTrafficType.addTrafficTypeCmd()
 +        cmd.physicalnetworkid = self.id
 +        cmd.traffictype = type
 +        return apiclient.addTrafficType(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all physical networks"""
 +
 +        cmd = listPhysicalNetworks.listPhysicalNetworksCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listPhysicalNetworks(cmd))
 +
 +class SecurityGroup:
 +    """Manage Security Groups"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, account=None, domainid=None,
 +               description=None, projectid=None):
 +        """Create security group"""
 +        cmd = createSecurityGroup.createSecurityGroupCmd()
 +
 +        cmd.name = services["name"]
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if description:
 +            cmd.description = description
 +        if projectid:
 +            cmd.projectid = projectid
 +
 +        return SecurityGroup(apiclient.createSecurityGroup(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Security Group"""
 +
 +        cmd = deleteSecurityGroup.deleteSecurityGroupCmd()
 +        cmd.id = self.id
 +        apiclient.deleteSecurityGroup(cmd)
 +
 +    def authorize(self, apiclient, services,
 +                  account=None, domainid=None, projectid=None):
 +        """Authorize Ingress Rule"""
 +
 +        cmd = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressCmd()
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        if account:
 +            cmd.account = account
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +        cmd.securitygroupid = self.id
 +        cmd.protocol = services["protocol"]
 +
 +        if services["protocol"] == 'ICMP':
 +            cmd.icmptype = -1
 +            cmd.icmpcode = -1
 +        else:
 +            cmd.startport = services["startport"]
 +            cmd.endport = services["endport"]
 +
 +        cmd.cidrlist = services["cidrlist"]
 +        return (apiclient.authorizeSecurityGroupIngress(cmd).__dict__)
 +
 +    def revoke(self, apiclient, id):
 +        """Revoke ingress rule"""
 +
 +        cmd = revokeSecurityGroupIngress.revokeSecurityGroupIngressCmd()
 +        cmd.id = id
 +        return apiclient.revokeSecurityGroupIngress(cmd)
 +
 +    def authorizeEgress(self, apiclient, services, account=None, domainid=None,
 +                        projectid=None, user_secgrp_list={}):
 +        """Authorize Egress Rule"""
 +
 +        cmd = authorizeSecurityGroupEgress.authorizeSecurityGroupEgressCmd()
 +
 +        if domainid:
 +            cmd.domainid = domainid
 +        if account:
 +            cmd.account = account
 +
 +        if projectid:
 +            cmd.projectid = projectid
 +        cmd.securitygroupid = self.id
 +        cmd.protocol = services["protocol"]
 +
 +        if services["protocol"] == 'ICMP':
 +            cmd.icmptype = -1
 +            cmd.icmpcode = -1
 +        else:
 +            cmd.startport = services["startport"]
 +            cmd.endport = services["endport"]
 +
 +        cmd.cidrlist = services["cidrlist"]
 +
 +        cmd.usersecuritygrouplist = []
 +        for account, group in user_secgrp_list.items():
 +            cmd.usersecuritygrouplist.append({
 +                                            'account': account,
 +                                            'group': group
 +                                           })
 +
 +        return (apiclient.authorizeSecurityGroupEgress(cmd).__dict__)
 +
 +    def revokeEgress(self, apiclient, id):
 +        """Revoke Egress rule"""
 +
 +        cmd = revokeSecurityGroupEgress.revokeSecurityGroupEgressCmd()
 +        cmd.id = id
 +        return apiclient.revokeSecurityGroupEgress(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all security groups."""
 +
 +        cmd = listSecurityGroups.listSecurityGroupsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listSecurityGroups(cmd))
 +
 +
 +class Project:
 +    """Manage Project life cycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, account=None, domainid=None):
 +        """Create project"""
 +
 +        cmd = createProject.createProjectCmd()
 +        cmd.displaytext = services["displaytext"]
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +
 +        return Project(apiclient.createProject(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Delete Project"""
 +
 +        cmd = deleteProject.deleteProjectCmd()
 +        cmd.id = self.id
 +        apiclient.deleteProject(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Updates the project"""
 +
 +        cmd = updateProject.updateProjectCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updateProject(cmd)
 +
 +    def activate(self, apiclient):
 +        """Activates the suspended project"""
 +
 +        cmd = activateProject.activateProjectCmd()
 +        cmd.id = self.id
 +        return apiclient.activateProject(cmd)
 +
 +    def suspend(self, apiclient):
 +        """Suspend the active project"""
 +
 +        cmd = suspendProject.suspendProjectCmd()
 +        cmd.id = self.id
 +        return apiclient.suspendProject(cmd)
 +
 +    def addAccount(self, apiclient, account=None, email=None):
 +        """Add account to project"""
 +
 +        cmd = addAccountToProject.addAccountToProjectCmd()
 +        cmd.projectid = self.id
 +        if account:
 +            cmd.account = account
 +        if email:
 +            cmd.email = email
 +        return apiclient.addAccountToProject(cmd)
 +
 +    def deleteAccount(self, apiclient, account):
 +        """Delete account from project"""
 +
 +        cmd = deleteAccountFromProject.deleteAccountFromProjectCmd()
 +        cmd.projectid = self.id
 +        cmd.account = account
 +        return apiclient.deleteAccountFromProject(cmd)
 +
 +    @classmethod
 +    def listAccounts(cls, apiclient, **kwargs):
 +        """Lists all accounts associated with projects."""
 +
 +        cmd = listProjectAccounts.listProjectAccountsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listProjectAccounts(cmd))
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists all projects."""
 +
 +        cmd = listProjects.listProjectsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listProjects(cmd))
 +
 +
 +class ProjectInvitation:
 +    """Manage project invitations"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def update(cls, apiclient, projectid, accept, account=None, token=None):
 +        """Updates the project invitation for that account"""
 +
 +        cmd = updateProjectInvitation.updateProjectInvitationCmd()
 +        cmd.projectid = projectid
 +        cmd.accept = accept
 +        if account:
 +            cmd.account = account
 +        if token:
 +            cmd.token = token
 +
 +        return (apiclient.updateProjectInvitation(cmd).__dict__)
 +
 +    def delete(self, apiclient, id):
 +        """Deletes the project invitation"""
 +
 +        cmd = deleteProjectInvitation.deleteProjectInvitationCmd()
 +        cmd.id = id
 +        return apiclient.deleteProjectInvitation(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists project invitations"""
 +
 +        cmd = listProjectInvitations.listProjectInvitationsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listProjectInvitations(cmd))
 +
 +
 +class Configurations:
 +    """Manage Configuration"""
 +
 +    @classmethod
 +    def update(cls, apiclient, name, value=None):
 +        """Updates the specified configuration"""
 +
 +        cmd = updateConfiguration.updateConfigurationCmd()
 +        cmd.name = name
 +        cmd.value = value
 +        apiclient.updateConfiguration(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """Lists configurations"""
 +
 +        cmd = listConfigurations.listConfigurationsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listConfigurations(cmd))
 +
 +
 +class NetScaler:
 +    """Manage external netscaler device"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def add(cls, apiclient, services, physicalnetworkid, username=None, password=None):
 +        """Add external netscaler device to cloudstack"""
 +
 +        cmd = addNetscalerLoadBalancer.addNetscalerLoadBalancerCmd()
 +        cmd.physicalnetworkid = physicalnetworkid
 +        if username:
 +            cmd.username = username
 +        else:
 +            cmd.username = services["username"]
 +
 +        if password:
 +            cmd.password = password
 +        else:
 +            cmd.password = services["password"]
 +
 +        cmd.networkdevicetype = services["networkdevicetype"]
 +
 +        # Generate the URL
 +        url = 'https://' + str(services["ipaddress"]) + '?'
 +        url = url + 'publicinterface=' + str(services["publicinterface"]) + '&'
 +        url = url + 'privateinterface=' + str(services["privateinterface"]) + '&'
 +        url = url + 'numretries=' + str(services["numretries"]) + '&'
 +
 +        if not services["lbdevicededicated"] and "lbdevicecapacity" in services:
 +            url = url + 'lbdevicecapacity=' + str(services["lbdevicecapacity"]) + '&'
 +
 +        url = url + 'lbdevicededicated=' + str(services["lbdevicededicated"])
 +
 +        cmd.url = url
 +        return NetScaler(apiclient.addNetscalerLoadBalancer(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Deletes a netscaler device from CloudStack"""
 +
 +        cmd = deleteNetscalerLoadBalancer.deleteNetscalerLoadBalancerCmd()
 +        cmd.lbdeviceid = self.lbdeviceid
 +        apiclient.deleteNetscalerLoadBalancer(cmd)
 +        return
 +
 +    def configure(self, apiclient, **kwargs):
 +        """List already registered netscaler devices"""
 +
 +        cmd = configureNetscalerLoadBalancer.configureNetscalerLoadBalancerCmd()
 +        cmd.lbdeviceid = self.lbdeviceid
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.configureNetscalerLoadBalancer(cmd))
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List already registered netscaler devices"""
 +
 +        cmd = listNetscalerLoadBalancers.listNetscalerLoadBalancersCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listNetscalerLoadBalancers(cmd))
 +
 +
 +class NetworkServiceProvider:
 +    """Manage network serivce providers for CloudStack"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def add(cls, apiclient, name, physicalnetworkid, servicelist):
 +        """Adds network service provider"""
 +
 +        cmd = addNetworkServiceProvider.addNetworkServiceProviderCmd()
 +        cmd.name = name
 +        cmd.physicalnetworkid = physicalnetworkid
 +        cmd.servicelist = servicelist
 +        return NetworkServiceProvider(apiclient.addNetworkServiceProvider(cmd).__dict__)
 +
 +    def delete(self, apiclient):
 +        """Deletes network service provider"""
 +
 +        cmd = deleteNetworkServiceProvider.deleteNetworkServiceProviderCmd()
 +        cmd.id = self.id
 +        return apiclient.deleteNetworkServiceProvider(cmd)
 +
 +    def update(self, apiclient, **kwargs):
 +        """Updates network service provider"""
 +
 +        cmd = updateNetworkServiceProvider.updateNetworkServiceProviderCmd()
 +        cmd.id = self.id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updateNetworkServiceProvider(cmd)
 +
 +    @classmethod
 +    def update(cls, apiclient, id, **kwargs):
 +        """Updates network service provider"""
 +
 +        cmd = updateNetworkServiceProvider.updateNetworkServiceProviderCmd()
 +        cmd.id = id
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return apiclient.updateNetworkServiceProvider(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List network service providers"""
 +
 +        cmd = listNetworkServiceProviders.listNetworkServiceProvidersCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listNetworkServiceProviders(cmd))
 +
 +class VpcOffering:
 +    """Manage VPC offerings"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services):
 +        """Create vpc offering"""
 +
 +        cmd = createVPCOffering.createVPCOfferingCmd()
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        cmd.displaytext = services["displaytext"]
 +        cmd.supportedServices = services["supportedservices"]
 +        return VpcOffering(apiclient.createVPCOffering(cmd).__dict__)
 +
 +    def update(self, apiclient, name=None, displaytext=None, state=None):
 +        """Updates existing VPC offering"""
 +
 +        cmd = updateVPCOffering.updateVPCOfferingCmd()
 +        cmd.id = self.id
 +        if name:
 +            cmd.name = name
 +        if displaytext:
 +            cmd.displaytext = displaytext
 +        if state:
 +            cmd.state = state
 +        return apiclient.updateVPCOffering(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List the VPC offerings based on criteria specified"""
 +
 +        cmd = listVPCOfferings.listVPCOfferingsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVPCOfferings(cmd))
 +
 +    def delete(self, apiclient):
 +        """Deletes existing VPC offering"""
 +
 +        cmd = deleteVPCOffering.deleteVPCOfferingCmd()
 +        cmd.id = self.id
 +        return apiclient.deleteVPCOffering(cmd)
 +
 +
 +class VPC:
 +    """Manage Virtual Private Connection"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, vpcofferingid,
 +               zoneid, networkDomain=None, account=None, domainid=None):
 +        """Creates the virtual private connection (VPC)"""
 +
 +        cmd = createVPC.createVPCCmd()
 +        cmd.name = "-".join([services["name"], random_gen()])
 +        cmd.displaytext = "-".join([services["displaytext"], random_gen()])
 +        cmd.vpcofferingid = vpcofferingid
 +        cmd.zoneid = zoneid
 +        cmd.cidr = services["cidr"]
 +        if account:
 +            cmd.account = account
 +        if domainid:
 +            cmd.domainid = domainid
 +        if networkDomain:
 +            cmd.networkDomain = networkDomain
 +        return VPC(apiclient.createVPC(cmd).__dict__)
 +
 +    def update(self, apiclient, name=None, displaytext=None):
 +        """Updates VPC configurations"""
 +
 +        cmd = updateVPC.updateVPCCmd()
 +        cmd.id = self.id
 +        if name:
 +            cmd.name = name
 +        if displaytext:
 +            cmd.displaytext = displaytext
 +        return (apiclient.updateVPC(cmd))
 +
 +    def delete(self, apiclient):
 +        """Delete VPC network"""
 +
 +        cmd = deleteVPC.deleteVPCCmd()
 +        cmd.id = self.id
 +        return apiclient.deleteVPC(cmd)
 +
 +    def restart(self, apiclient):
 +        """Restarts the VPC connections"""
 +
 +        cmd = restartVPC.restartVPCCmd()
 +        cmd.id = self.id
 +        return apiclient.restartVPC(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List VPCs"""
 +
 +        cmd = listVPCs.listVPCsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVPCs(cmd))
 +
 +class AffinityGroup:
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, services, account=None, domainid=None):
 +        agCmd = createAffinityGroup.createAffinityGroupCmd()
 +        agCmd.name = services['name']
 +        agCmd.displayText = services['displaytext'] if 'displaytext' in services else services['name']
 +        agCmd.type = services['type']
 +        agCmd.account = services['account'] if 'account' in services else account
 +        agCmd.domainid = services['domainid'] if 'domainid' in services else domainid
 +        return AffinityGroup(apiclient.createAffinityGroup(agCmd).__dict__)
 +
 +    def update(self, apiclient):
 +        pass
 +
 +    def delete(self, apiclient):
 +        cmd = deleteAffinityGroup.deleteAffinityGroupCmd()
 +        cmd.id = self.id
 +        return apiclient.deleteVPC(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        cmd = listAffinityGroups.listAffinityGroupsCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listVPCs(cmd))
 +
 +class VNMC:
 +    """Manage VNMC lifecycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    def create(cls, apiclient, hostname, username, password, physicalnetworkid):
 +        """Registers VNMC appliance"""
 +
 +        cmd = addCiscoVnmcResource.addCiscoVnmcResourceCmd()
 +        cmd.hostname = hostname
 +        cmd.username = username
 +        cmd.password = password
 +        cmd.physicalnetworkid = physicalnetworkid
 +        return VNMC(apiclient.addCiscoVnmcResource(cmd))
 +
 +    def delete(self, apiclient):
 +        """Removes VNMC appliance"""
 +
 +        cmd = deleteCiscoVnmcResource.deleteCiscoVnmcResourceCmd()
 +        cmd.resourceid = self.resourceid
 +        return apiclient.deleteCiscoVnmcResource(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List VNMC appliances"""
 +
 +        cmd = listCiscoVnmcResources.listCiscoVnmcResourcesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listCiscoVnmcResources(cmd))
 +
 +class ASA1000V:
 +    """Manage ASA 1000v lifecycle"""
 +
 +    def __init__(self, items):
 +        self.__dict__.update(items)
 +
 +    @classmethod
 +    def create(cls, apiclient, hostname, insideportprofile, clusterid, physicalnetworkid):
 +        """Registers ASA 1000v appliance"""
 +
 +        cmd = addCiscoAsa1000vResource.addCiscoAsa1000vResourceCmd()
 +        cmd.hostname = hostname
 +        cmd.insideportprofile = insideportprofile
 +        cmd.clusterid = clusterid
 +        cmd.physicalnetworkid = physicalnetworkid
 +        return ASA1000V(apiclient.addCiscoAsa1000vResource(cmd))
 +
 +    def delete(self, apiclient):
 +        """Removes ASA 1000v appliance"""
 +
 +        cmd = deleteCiscoAsa1000vResource.deleteCiscoAsa1000vResourceCmd()
 +        cmd.resourceid = self.resourceid
 +        return apiclient.deleteCiscoAsa1000vResource(cmd)
 +
 +    @classmethod
 +    def list(cls, apiclient, **kwargs):
 +        """List ASA 1000v appliances"""
 +
 +        cmd = listCiscoAsa1000vResources.listCiscoAsa1000vResourcesCmd()
 +        [setattr(cmd, k, v) for k, v in kwargs.items()]
 +        return(apiclient.listCiscoAsa1000vResources(cmd))

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4abd9292/ui/scripts/zoneWizard.js
----------------------------------------------------------------------


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

Posted by ts...@apache.org.
Rename widget 'plugins' to 'pluginListing'

For better clarity on its function, rename the 'plugins' widget to 'pluginListing,'
as it does not handle the actual plugin logic.


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

Branch: refs/heads/marvin_refactor
Commit: fca7b3ef22b00f6003fbb6fa601c9b7c1a79dcec
Parents: 7a4f70f
Author: Brian Federle <br...@citrix.com>
Authored: Thu Apr 18 10:38:03 2013 -0700
Committer: Brian Federle <br...@citrix.com>
Committed: Thu Apr 18 10:49:45 2013 -0700

----------------------------------------------------------------------
 ui/index.jsp                          |    2 +-
 ui/scripts/plugins.js                 |    4 +-
 ui/scripts/ui-custom/pluginListing.js |  109 ++++++++++++++++++++++++++++
 ui/scripts/ui-custom/plugins.js       |  109 ----------------------------
 4 files changed, 111 insertions(+), 113 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fca7b3ef/ui/index.jsp
----------------------------------------------------------------------
diff --git a/ui/index.jsp b/ui/index.jsp
index 46f49f0..550661e 100644
--- a/ui/index.jsp
+++ b/ui/index.jsp
@@ -1681,7 +1681,7 @@ under the License.
     <script type="text/javascript" src="scripts/vm_snapshots.js?t=<%=now%>"></script>  
 
     <!-- Plugins -->
-    <script type="text/javascript" src="scripts/ui-custom/plugins.js?t=<%=now%>"></script>
+    <script type="text/javascript" src="scripts/ui-custom/pluginListing.js?t=<%=now%>"></script>
     <script type="text/javascript" src="plugins/plugins.js?t=<%=now%>"></script>
     <script type="text/javascript" src="scripts/plugins.js?t=<%=now%>"></script>
   </body>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fca7b3ef/ui/scripts/plugins.js
----------------------------------------------------------------------
diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js
index 5a33d56..d3e0705 100644
--- a/ui/scripts/plugins.js
+++ b/ui/scripts/plugins.js
@@ -51,7 +51,7 @@
   
   cloudStack.sections.plugins = {
     title: 'label.plugins',
-    show: cloudStack.uiCustom.plugins
+    show: cloudStack.uiCustom.pluginListing
   };
 
   // Load plugins
@@ -70,7 +70,5 @@
         ui: pluginAPI
       });
     });
-
-    // Load CSS
   });
 }(jQuery, cloudStack, require));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fca7b3ef/ui/scripts/ui-custom/pluginListing.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui-custom/pluginListing.js b/ui/scripts/ui-custom/pluginListing.js
new file mode 100644
index 0000000..3dcce98
--- /dev/null
+++ b/ui/scripts/ui-custom/pluginListing.js
@@ -0,0 +1,109 @@
+// 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
+// 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.
+(function($, cloudStack) {
+  var elems = {
+    pluginItem: function(args) {
+      var id = args.id;
+      var title = args.title;
+      var desc = args.desc;
+      var iconURL = args.iconURL;
+      var $pluginItem = $('<li>').addClass('plugin-item').addClass(id);
+      var $title = $('<span>').addClass('title').html(title);
+      var $desc = $('<span>').addClass('desc').html(desc);
+      var $icon = $('<span>').addClass('icon').append(
+        $('<img>').attr({ src: iconURL })
+      );
+
+      $pluginItem.append(
+        $icon, $title, $desc
+      );
+
+      return $pluginItem;
+    },
+    pluginListing: function(args) {
+      var plugins = args.plugins;
+      var $plugins = $('<ul>');
+      var $pluginsListing = $('<div>').addClass('plugins-listing');
+
+      $(plugins).each(function() {
+        var plugin = this;
+        var $plugin = elems.pluginItem({
+          id: plugin.id,
+          title: plugin.title,
+          desc: plugin.desc,
+          iconURL: 'plugins/' + plugin.id + '/icon.png'
+        });
+        var $browser = $('#browser .container');
+
+        $plugin.click(function() {
+          $browser.cloudBrowser('addPanel', {
+            title: plugin.title,
+            $parent: $('.panel:first'),
+            complete: function($panel) {
+              $panel.detailView({
+                name: 'Plugin details',
+                tabs: {
+                  details: {
+                    title: 'label.plugin.details',
+                    fields: [
+                      {
+                        name: { label: 'label.name' }
+                      },
+                      {
+                        desc: { label: 'label.description' },
+                        externalLink: {
+                          isExternalLink: true,
+                          label: 'label.external.link'
+                        }
+                      },
+                      {
+                        authorName: { label: 'label.author.name' },
+                        authorEmail: { label: 'label.author.email' },
+                        id: { label: 'label.id' }
+                      }
+                    ],
+                    dataProvider: function(args) {
+                      args.response.success({ data: plugin });
+                    }
+                  }
+                }
+              });
+            }
+          });
+        });
+
+        $plugin.appendTo($plugins);
+      });
+
+      $pluginsListing.append($plugins);
+
+      return $pluginsListing;
+    }
+  };
+
+  cloudStack.uiCustom.pluginListing = function() {
+    var plugins = cloudStack.plugins;
+
+    return elems.pluginListing({
+      plugins: $(plugins).map(function(index, pluginID) {
+        var plugin = cloudStack.plugins[pluginID].config;
+
+        return $.extend(plugin, { id: pluginID });
+      })
+    });
+  };
+}(jQuery, cloudStack));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fca7b3ef/ui/scripts/ui-custom/plugins.js
----------------------------------------------------------------------
diff --git a/ui/scripts/ui-custom/plugins.js b/ui/scripts/ui-custom/plugins.js
deleted file mode 100644
index aaf9531..0000000
--- a/ui/scripts/ui-custom/plugins.js
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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
-// 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.
-(function($, cloudStack) {
-  var elems = {
-    pluginItem: function(args) {
-      var id = args.id;
-      var title = args.title;
-      var desc = args.desc;
-      var iconURL = args.iconURL;
-      var $pluginItem = $('<li>').addClass('plugin-item').addClass(id);
-      var $title = $('<span>').addClass('title').html(title);
-      var $desc = $('<span>').addClass('desc').html(desc);
-      var $icon = $('<span>').addClass('icon').append(
-        $('<img>').attr({ src: iconURL })
-      );
-
-      $pluginItem.append(
-        $icon, $title, $desc
-      );
-
-      return $pluginItem;
-    },
-    pluginListing: function(args) {
-      var plugins = args.plugins;
-      var $plugins = $('<ul>');
-      var $pluginsListing = $('<div>').addClass('plugins-listing');
-
-      $(plugins).each(function() {
-        var plugin = this;
-        var $plugin = elems.pluginItem({
-          id: plugin.id,
-          title: plugin.title,
-          desc: plugin.desc,
-          iconURL: 'plugins/' + plugin.id + '/icon.png'
-        });
-        var $browser = $('#browser .container');
-
-        $plugin.click(function() {
-          $browser.cloudBrowser('addPanel', {
-            title: plugin.title,
-            $parent: $('.panel:first'),
-            complete: function($panel) {
-              $panel.detailView({
-                name: 'Plugin details',
-                tabs: {
-                  details: {
-                    title: 'label.plugin.details',
-                    fields: [
-                      {
-                        name: { label: 'label.name' }
-                      },
-                      {
-                        desc: { label: 'label.description' },
-                        externalLink: {
-                          isExternalLink: true,
-                          label: 'label.external.link'
-                        }
-                      },
-                      {
-                        authorName: { label: 'label.author.name' },
-                        authorEmail: { label: 'label.author.email' },
-                        id: { label: 'label.id' }
-                      }
-                    ],
-                    dataProvider: function(args) {
-                      args.response.success({ data: plugin });
-                    }
-                  }
-                }
-              });
-            }
-          });
-        });
-
-        $plugin.appendTo($plugins);
-      });
-
-      $pluginsListing.append($plugins);
-
-      return $pluginsListing;
-    }
-  };
-
-  cloudStack.uiCustom.plugins = function() {
-    var plugins = cloudStack.plugins;
-
-    return elems.pluginListing({
-      plugins: $(plugins).map(function(index, pluginID) {
-        var plugin = cloudStack.plugins[pluginID].config;
-
-        return $.extend(plugin, { id: pluginID });
-      })
-    });
-  };
-}(jQuery, cloudStack));


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

Posted by ts...@apache.org.
CLOUDSTACK-1977: Add management setup directory to classpath

This way the DB upgrade process can locate the SQL files


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

Branch: refs/heads/marvin_refactor
Commit: 9573f51d3b5c79209262c398c4f13897ceaa19a8
Parents: ce8c2eb
Author: Wido den Hollander <wi...@42on.com>
Authored: Thu Apr 18 21:32:08 2013 +0200
Committer: Wido den Hollander <wi...@42on.com>
Committed: Thu Apr 18 21:32:08 2013 +0200

----------------------------------------------------------------------
 packaging/debian/init/cloud-management |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9573f51d/packaging/debian/init/cloud-management
----------------------------------------------------------------------
diff --git a/packaging/debian/init/cloud-management b/packaging/debian/init/cloud-management
index 1e00831..8431eec 100755
--- a/packaging/debian/init/cloud-management
+++ b/packaging/debian/init/cloud-management
@@ -125,7 +125,7 @@ fi
 # Define other required variables
 CATALINA_PID="/var/run/$NAME.pid"
 BOOTSTRAP_CLASS=org.apache.catalina.startup.Bootstrap
-JSVC_CLASSPATH="/usr/share/java/commons-daemon.jar:$CATALINA_HOME/bin/bootstrap.jar:/etc/cloudstack/management"
+JSVC_CLASSPATH="/usr/share/java/commons-daemon.jar:$CATALINA_HOME/bin/bootstrap.jar:/etc/cloudstack/management:/usr/share/cloudstack-management/setup"
 
 # Look for Java Secure Sockets Extension (JSSE) JARs
 if [ -z "${JSSE_HOME}" -a -r "${JAVA_HOME}/jre/lib/jsse.jar" ]; then


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

Posted by ts...@apache.org.
Switched to yum upgrade vs yum install for RPM upgrade instructions

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 31531fa9a6662ef523bdb2e66ee961ae23093bf9
Parents: f4240e1
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 12:48:41 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 12:48:41 2013 -0400

----------------------------------------------------------------------
 docs/en-US/Release_Notes.xml |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/31531fa9/docs/en-US/Release_Notes.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml
index b07b584..d5311e4 100644
--- a/docs/en-US/Release_Notes.xml
+++ b/docs/en-US/Release_Notes.xml
@@ -4221,12 +4221,12 @@ gpgcheck=0
                             <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
                         </listitem>
                         <listitem id="rpm-master">
-                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package. This will pull in any other dependencies you need.</para>
-                            <programlisting language="Bash">$ sudo yum install cloudstack-management</programlisting>
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package by upgrading the older <filename>cloud-client</filename> package.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-client</programlisting>
                         </listitem>
                         <listitem id="kvm-agent-rpm">
-                            <para>For KVM hosts, you will need to upgrade the <filename>cloudstack-agent</filename> package:</para>
-                            <programlisting language="Bash">$ sudo yum install cloudstack-agent</programlisting>
+                            <para>For KVM hosts, you will need to upgrade the <filename>cloud-agent</filename> package, similarly installing the new version as <filename>cloudstack-agent</filename>.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-agent</programlisting>
                             <para>During the installation of <filename>cloudstack-agent</filename>, the RPM will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
                         </listitem>
                         <listitem>
@@ -4459,12 +4459,12 @@ gpgcheck=0
                             <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
                         </listitem>
                         <listitem id="rpm-master-302">
-                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package. This will pull in any other dependencies you need.</para>
-                            <programlisting language="Bash">$ sudo yum install cloudstack-management</programlisting>
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package by upgrading the older <filename>cloud-client</filename> package.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-client</programlisting>
                         </listitem>
                         <listitem id="kvm-agent-rpm-302">
-                            <para>For KVM hosts, you will need to upgrade the <filename>cloudstack-agent</filename> package:</para>
-                            <programlisting language="Bash">$ sudo yum install cloudstack-agent</programlisting>
+                            <para>For KVM hosts, you will need to upgrade the <filename>cloud-agent</filename> package, similarly installing the new version as <filename>cloudstack-agent</filename>.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-agent</programlisting>
                             <para>During the installation of <filename>cloudstack-agent</filename>, the RPM will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
                         </listitem>
                         <listitem>


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

Posted by ts...@apache.org.
appliance: Don't mkdir 70-persistent-net.rules for systemvms

Signed-off-by: Rohit Yadav <bh...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 81e1ba3bb406f9546f0d46ccbfa3fbbb35b762e2
Parents: ca6873a
Author: Rohit Yadav <bh...@apache.org>
Authored: Fri Apr 19 09:05:42 2013 +0530
Committer: Rohit Yadav <bh...@apache.org>
Committed: Fri Apr 19 09:05:42 2013 +0530

----------------------------------------------------------------------
 .../definitions/systemvmtemplate/cleanup.sh        |    1 -
 .../definitions/systemvmtemplate64/cleanup.sh      |    1 -
 2 files changed, 0 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/81e1ba3b/tools/appliance/definitions/systemvmtemplate/cleanup.sh
----------------------------------------------------------------------
diff --git a/tools/appliance/definitions/systemvmtemplate/cleanup.sh b/tools/appliance/definitions/systemvmtemplate/cleanup.sh
index 9e98ab0..701d8d8 100644
--- a/tools/appliance/definitions/systemvmtemplate/cleanup.sh
+++ b/tools/appliance/definitions/systemvmtemplate/cleanup.sh
@@ -12,7 +12,6 @@ rm /var/lib/dhcp/*
 # Make sure Udev doesn't block our network
 echo "cleaning up udev rules"
 rm /etc/udev/rules.d/70-persistent-net.rules
-mkdir /etc/udev/rules.d/70-persistent-net.rules
 rm -rf /dev/.udev/
 rm /lib/udev/rules.d/75-persistent-net-generator.rules
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/81e1ba3b/tools/appliance/definitions/systemvmtemplate64/cleanup.sh
----------------------------------------------------------------------
diff --git a/tools/appliance/definitions/systemvmtemplate64/cleanup.sh b/tools/appliance/definitions/systemvmtemplate64/cleanup.sh
index 9e98ab0..701d8d8 100644
--- a/tools/appliance/definitions/systemvmtemplate64/cleanup.sh
+++ b/tools/appliance/definitions/systemvmtemplate64/cleanup.sh
@@ -12,7 +12,6 @@ rm /var/lib/dhcp/*
 # Make sure Udev doesn't block our network
 echo "cleaning up udev rules"
 rm /etc/udev/rules.d/70-persistent-net.rules
-mkdir /etc/udev/rules.d/70-persistent-net.rules
 rm -rf /dev/.udev/
 rm /lib/udev/rules.d/75-persistent-net-generator.rules
 


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

Posted by ts...@apache.org.
Adding release plugin to pom


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

Branch: refs/heads/marvin_refactor
Commit: a51b566fb6eb70f6459f894c4c7dc3e75e610d7c
Parents: 6babaf9
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 15:03:11 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 16:13:18 2013 -0400

----------------------------------------------------------------------
 pom.xml |   16 ++++++++++++++++
 1 files changed, 16 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a51b566f/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index dbc3907..7d5b4c3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -237,6 +237,22 @@
     <defaultGoal>install</defaultGoal>
     <pluginManagement>
       <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-release-plugin</artifactId>
+          <version>2.2.1</version>
+          <executions>
+            <execution>
+              <id>default</id>
+              <goals>
+                <goal>perform</goal>
+              </goals>
+              <configuration>
+                <pomFileName>pom.xml</pomFileName>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
         <!--This plugin's configuration is used to store Eclipse m2e settings
           only. It has no influence on the Maven build itself. -->
         <plugin>


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

Posted by ts...@apache.org.
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;
+    }
 }


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

Posted by ts...@apache.org.
Removing inappropriate note about an upgrade *to* 3.0.2 in the *from* 3.0.2 section of the release notes

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: bf120917f99df0e3d03d50f619ea5809f4c914c4
Parents: 7023920
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 12:12:02 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 12:28:10 2013 -0400

----------------------------------------------------------------------
 docs/en-US/Release_Notes.xml |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/bf120917/docs/en-US/Release_Notes.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml
index 09cf2e2..2810269 100644
--- a/docs/en-US/Release_Notes.xml
+++ b/docs/en-US/Release_Notes.xml
@@ -4273,15 +4273,6 @@ Done restarting router(s).
             <para>This section will guide you from Citrix CloudStack 3.0.2 to Apache CloudStack 4.1.0. Sections that are hypervisor-specific will be called out with a note.</para>
             <orderedlist>
                 <listitem>
-                    <para>Ensure that you query your IP address usage records and process them or make a
-                        backup. During the upgrade you will lose the old IP address usage records.</para>
-                    <para>Starting in 3.0.2, the usage record format for IP addresses is the same as the rest
-                        of the usage types. Instead of a single record with the assignment and release dates,
-                        separate records are generated per aggregation period with start and end dates. After
-                        upgrading, any existing IP address usage records in the old format will no longer be
-                        available.</para>
-                </listitem>
-                <listitem>
                     <note>
                         <para>The following upgrade instructions apply only if you're using VMware hosts. If
                             you're not using VMware hosts, skip this step and move on to <xref linkend="stopping-usage-servers" />.</para>


[25/35] 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 c

Posted by ts...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/setup/db/db/schema-410to420.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-410to420.sql b/setup/db/db/schema-410to420.sql
index ce651a0..14aa2eb 100644
--- a/setup/db/db/schema-410to420.sql
+++ b/setup/db/db/schema-410to420.sql
@@ -23,7 +23,9 @@
 SET foreign_key_checks = 0;
 
 ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `max_hosts_per_cluster` int unsigned DEFAULT NULL COMMENT 'Max. hosts in cluster supported by hypervisor';
+ALTER TABLE `cloud`.`hypervisor_capabilities` ADD COLUMN `storage_motion_supported` int(1) unsigned DEFAULT 0 COMMENT 'Is storage motion supported';
 UPDATE `cloud`.`hypervisor_capabilities` SET `max_hosts_per_cluster`=32 WHERE `hypervisor_type`='VMware';
+INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_data_volumes_limit, storage_motion_supported) VALUES ('XenServer', '6.1.0', 50, 1, 13, 1);
 INSERT IGNORE INTO `cloud`.`hypervisor_capabilities`(hypervisor_type, hypervisor_version, max_guests_limit, security_group_enabled, max_hosts_per_cluster) VALUES ('VMware', '5.1', 128, 0, 32);
 DELETE FROM `cloud`.`configuration` where name='vmware.percluster.host.max';
 INSERT IGNORE INTO `cloud`.`configuration` VALUES ('Advanced', 'DEFAULT', 'AgentManager', 'xen.nics.max', '7', 'Maximum allowed nics for Vms created on Xen');

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/test/integration/component/test_storage_motion.py
----------------------------------------------------------------------
diff --git a/test/integration/component/test_storage_motion.py b/test/integration/component/test_storage_motion.py
new file mode 100644
index 0000000..cc55a08
--- /dev/null
+++ b/test/integration/component/test_storage_motion.py
@@ -0,0 +1,298 @@
+# 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.
+""" P1 tests for Storage motion
+"""
+#Import Local Modules
+import marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from nose.plugins.attrib import attr
+#Import System modules
+import time
+
+_multiprocess_shared_ = True
+class Services:
+    """Test VM Life Cycle Services
+    """
+
+    def __init__(self):
+        self.services = {
+                "disk_offering":{
+                    "displaytext": "Small",
+                    "name": "Small",
+                    "disksize": 1
+                },
+                "account": {
+                    "email": "test@test.com",
+                    "firstname": "Test",
+                    "lastname": "User",
+                    "username": "test",
+                    # Random characters are appended in create account to
+                    # ensure unique username generated each time
+                    "password": "password",
+                },
+                "small":
+                # Create a small virtual machine instance with disk offering
+                {
+                    "displayname": "testserver",
+                    "username": "root", # VM creds for SSH
+                    "password": "password",
+                    "ssh_port": 22,
+                    "hypervisor": 'XenServer',
+                    "privateport": 22,
+                    "publicport": 22,
+                    "protocol": 'TCP',
+                },
+                "service_offerings":
+                {
+                 "small":
+                    {
+                     # Small service offering ID to for change VM
+                     # service offering from medium to small
+                        "name": "Small Instance",
+                        "displaytext": "Small Instance",
+                        "cpunumber": 1,
+                        "cpuspeed": 100,
+                        "memory": 256,
+                    }
+                },
+                "template": {
+                    "displaytext": "Cent OS Template",
+                    "name": "Cent OS Template",
+                    "passwordenabled": True,
+                },
+            "diskdevice": '/dev/xvdd',
+            # Disk device where ISO is attached to instance
+            "mount_dir": "/mnt/tmp",
+            "sleep": 60,
+            "timeout": 10,
+            #Migrate VM to hostid
+            "ostype": 'CentOS 5.3 (64-bit)',
+            # CentOS 5.3 (64-bit)
+        }
+
+class TestStorageMotion(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.api_client = super(TestStorageMotion, cls).getClsTestClient().getApiClient()
+        cls.services = Services().services
+
+        # Get Zone, Domain and templates
+        domain = get_domain(cls.api_client, cls.services)
+        zone = get_zone(cls.api_client, cls.services)
+        cls.services['mode'] = zone.networktype
+
+        template = get_template(
+                            cls.api_client,
+                            zone.id,
+                            cls.services["ostype"]
+                            )
+        # Set Zones and disk offerings
+        cls.services["small"]["zoneid"] = zone.id
+        cls.services["small"]["template"] = template.id
+
+        # Create VMs, NAT Rules etc
+        cls.account = Account.create(
+                            cls.api_client,
+                            cls.services["account"],
+                            domainid=domain.id
+                            )
+
+        cls.small_offering = ServiceOffering.create(
+                                    cls.api_client,
+                                    cls.services["service_offerings"]["small"]
+                                    )
+
+        #create a virtual machine
+        cls.virtual_machine = VirtualMachine.create(
+                                        cls.api_client,
+                                        cls.services["small"],
+                                        accountid=cls.account.account.name,
+                                        domainid=cls.account.account.domainid,
+                                        serviceofferingid=cls.small_offering.id,
+                                        mode=cls.services["mode"]
+                                        )
+        cls._cleanup = [
+                        cls.small_offering,
+                        cls.account
+                        ]
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.api_client = super(TestStorageMotion, cls).getClsTestClient().getApiClient()
+        cleanup_resources(cls.api_client, cls._cleanup)
+        return
+
+    def setUp(self):
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.cleanup = []
+
+    def tearDown(self):
+        #Clean up, terminate the created ISOs
+        cleanup_resources(self.apiclient, self.cleanup)
+        return
+
+    @attr(tags = ["advanced", "basic", "multicluster", "storagemotion", "xenserver"])
+    def test_01_migrate_vm_with_volume(self):
+        """Test migrate virtual machine with its volumes
+        """
+        # Validate the following
+        # 1. List hosts for migration of a vm. Pick a host that
+        # requires storage motion too.
+        # 2. Migrate vm to a host.
+        # 3. listVM command should return this VM.State of this VM
+        #    should be "Running" and the host should be the host
+        #    to which the VM was migrated to in a different cluster
+
+        hosts = Host.listForMigration(
+                          self.apiclient,
+                          virtualmachineid=self.virtual_machine.id
+                          )
+
+        self.assertEqual(
+                         isinstance(hosts, list),
+                         True,
+                         "Check the number of hosts in the zone"
+                         )
+
+        # Migrate to a host that requires storage motion
+        hosts[:] = [host for host in hosts if host.requiresStorageMotion]
+
+        host = hosts[0]
+        self.debug("Migrating VM-ID: %s to Host: %s" % (
+                                        self.virtual_machine.id,
+                                        host.id
+                                        ))
+
+        cmd = migrateVirtualMachineWithVolume.migrateVirtualMachineWithVolumeCmd()
+        cmd.hostid = host.id
+        cmd.virtualmachineid = self.virtual_machine.id
+        self.apiclient.migrateVirtualMachineWithVolume(cmd)
+
+        list_vm_response = list_virtual_machines(
+                                            self.apiclient,
+                                            id=self.virtual_machine.id
+                                            )
+        self.assertEqual(
+                        isinstance(list_vm_response, list),
+                        True,
+                        "Check list response returns a valid list"
+                        )
+
+        self.assertNotEqual(
+                            list_vm_response,
+                            None,
+                            "Check virtual machine is listVirtualMachines"
+                            )
+
+        vm_response = list_vm_response[0]
+
+        self.assertEqual(
+                        vm_response.id,
+                        self.virtual_machine.id,
+                        "Check virtual machine ID of migrated VM"
+                        )
+
+        self.assertEqual(
+                        vm_response.hostid,
+                        host.id,
+                        "Check destination hostID of migrated VM"
+                        )
+
+        self.assertEqual(
+                        vm_response.state,
+                        'Running',
+                        "Check the state of VM"
+                        )
+        return
+
+    @attr(tags = ["advanced", "basic", "multipool", "storagemotion", "xenserver"])
+    def test_02_migrate_volume(self):
+        """Test migrate volume of a running vm
+        """
+        # Validate the following
+        # 1. List all the volumes of a vm. For each volume do step 2 to 4.
+        # 2. List storage pools for migrating volume of a vm. Multiple
+        #    storage pools should be present in the cluster.
+        # 3. Migrate volume of the vm to another pool.
+        # 4. Check volume is present in the new pool and is in Ready state.
+
+        list_volumes_response = list_volumes(
+                                    self.apiclient,
+                                    virtualmachineid=self.virtual_machine.id,
+                                    listall=True
+                                    )
+        self.assertEqual(
+                         isinstance(list_volumes_response, list),
+                         True,
+                         "Check list volumes response for valid list"
+                        )
+        self.assertNotEqual(
+                        list_volumes_response,
+                        None,
+                        "Check if volume exists in ListVolumes"
+                        )
+
+        for volume in list_volumes_response:
+            pools = StoragePool.listForMigration(
+                              self.apiclient,
+                              id=volume.id
+                              )
+            pool = pools[0]
+            self.debug("Migrating Volume-ID: %s to Pool: %s" % (
+                                volume.id,
+                                pool.id
+                                ))
+            Volume.migrate(
+                           self.apiclient,
+                           volumeid=volume.id,
+                           storageid=pool.id,
+                           livemigrate='true'
+                           )
+            migrated_volume_response = list_volumes(
+                                             self.apiclient,
+                                             id=volume.id
+                                             )
+            self.assertEqual(
+                             isinstance(migrated_volume_response, list),
+                             True,
+                             "Check list volumes response for valid list"
+                             )
+            self.assertNotEqual(
+                                migrated_volume_response,
+                                None,
+                                "Check if volume exists in ListVolumes"
+                                )
+            migrated_volume = migrated_volume_response[0]
+            self.assertEqual(
+                             migrated_volume.state,
+                             'Ready',
+                             "Check migrated volume is in Ready state"
+                             )
+            self.assertEqual(
+                             migrated_volume.storage,
+                             pool.name,
+                             "Check volume is on migrated pool"
+                             )
+
+        return
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/tools/marvin/marvin/integration/lib/base.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py
index 0185c87..915d478 100755
--- a/tools/marvin/marvin/integration/lib/base.py
+++ b/tools/marvin/marvin/integration/lib/base.py
@@ -539,6 +539,13 @@ class Volume:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.resizeVolume(cmd))
 
+    @classmethod
+    def migrate(cls, apiclient, **kwargs):
+        """Migrate a volume"""
+        cmd = migrateVolume.migrateVolumeCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.migrateVolume(cmd))
+
 class Snapshot:
     """Manage Snapshot Lifecycle
     """
@@ -1493,6 +1500,14 @@ class Host:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.listHosts(cmd))
 
+    @classmethod
+    def listForMigration(cls, apiclient, **kwargs):
+        """List all Hosts for migration matching criteria"""
+
+        cmd = findHostsForMigration.findHostsForMigrationCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.findHostsForMigration(cmd))
+
 
 class StoragePool:
     """Manage Storage pools (Primary Storage)"""
@@ -1554,6 +1569,13 @@ class StoragePool:
         [setattr(cmd, k, v) for k, v in kwargs.items()]
         return(apiclient.listStoragePools(cmd))
 
+    @classmethod
+    def listForMigration(cls, apiclient, **kwargs):
+        """List all storage pools for migration matching criteria"""
+
+        cmd = findStoragePoolsForMigration.findStoragePoolsForMigrationCmd()
+        [setattr(cmd, k, v) for k, v in kwargs.items()]
+        return(apiclient.findStoragePoolsForMigration(cmd))
 
 class Network:
     """Manage Network pools"""


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

Posted by ts...@apache.org.
Adding RPM and DEB upgrade steps from 3.0.2 to 4.1.0 in release notes

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: f4240e1cea58be0ea7b50c77a018d7c63e3faf15
Parents: bf12091
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 12:25:26 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 12:28:10 2013 -0400

----------------------------------------------------------------------
 docs/en-US/Release_Notes.xml |  114 ++++++++++++++++++++++++++++++++-----
 1 files changed, 99 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f4240e1c/docs/en-US/Release_Notes.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml
index 2810269..b07b584 100644
--- a/docs/en-US/Release_Notes.xml
+++ b/docs/en-US/Release_Notes.xml
@@ -4382,23 +4382,107 @@ Done restarting router(s).
                         the community provided yum/apt repositories to gain access to the &PRODUCT;
                         binaries.</para>
                 </listitem>
-                <listitem>
-                    <para>After you have configured an appropriate yum or apt repository, you may execute the
-                        one of the following commands as appropriate for your environment in order to upgrade
-                        &PRODUCT;: <programlisting><prompt>#</prompt> <command>yum</command> update cloud-*</programlisting>
-                        <programlisting><prompt>#</prompt> <command>apt-get</command> update
-                            <prompt>#</prompt> <command>apt-get</command> upgrade cloud-*</programlisting>
-                    </para>
-                    <para>You will, of course, have to agree to the changes suggested by Yum or APT.</para>
-                    <note>
-                        <para>If the upgrade output includes a message similar to the following, then some
-                            custom content was found in your old components.xml, and you need to merge the two
-                            files:</para>
-                        <programlisting>warning: /etc/cloud/management/components.xml created as /etc/cloud/management/components.xml.rpmnew </programlisting>
-                        <para>Instructions follow in the next step.</para>
+                <listitem id="upgrade-deb-packages-302">
+                    <para>If you are using Ubuntu, follow this procedure to upgrade your packages. If not, skip to step <xref linkend="upgrade-rpm-packages-302" />.</para> 
+                    <note><title>Community Packages</title>
+                        <para>This section assumes you're using the community supplied packages for &PRODUCT;. If you've created your own packages and APT repository, substitute your own URL for the ones used in these examples.</para>
                     </note>
+                    <orderedlist id="debsteps-302">
+                        <listitem>
+                            <para>The first order of business will be to change the sources list for each system with &PRODUCT; packages. This means all management servers, and any hosts that have the KVM agent. (No changes should be necessary for hosts that are running VMware or Xen.)</para>
+                            <para>Start by opening <filename>/etc/apt/sources.list.d/cloudstack.list</filename> on any systems that have &PRODUCT; packages installed.</para>
+                            <para>This file should have one line, which contains:</para>
+                            <programlisting language="Bash">deb http://cloudstack.apt-get.eu/ubuntu precise 4.0</programlisting>
+                            <para>We'll change it to point to the new package repository:</para>
+                            <programlisting language="Bash">deb http://cloudstack.apt-get.eu/ubuntu precise 4.1</programlisting>
+                            <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Now update your apt package list:</para>
+                            <programlisting language="Bash">$ sudo apt-get update</programlisting>
+                        </listitem>
+                        <listitem id="deb-master-302">
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package. This will pull in any other dependencies you need.</para>
+                            <programlisting language="Bash">$ sudo apt-get install cloudstack-management</programlisting>
+                        </listitem>
+                        <listitem id="kvm-agent-deb-302">
+                            <para>You will need to manually install the <filename>cloudstack-agent</filename> package:</para>
+                            <programlisting language="Bash">$ sudo apt-get install cloudstack-agent</programlisting>
+                            <para>During the installation of <filename>cloudstack-agent</filename>, APT will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
+                            <para>When prompted whether you wish to keep your configuration, say Yes.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Verify that the file <filename>/etc/cloudstack/agent/environment.properties</filename> has a line that reads:</para>
+                            <programlisting language="Bash">paths.script=/usr/share/cloudstack-common</programlisting>
+                            <para>If not, add the line.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Restart the agent:</para>
+                            <programlisting language="Bash">
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
+                            </programlisting>
+                        </listitem>
+                        <listitem>
+                            <para>During the upgrade, <filename>log4j-cloud.xml</filename> was simply copied over, so the logs will continue to be added to <filename>/var/log/cloud/agent/agent.log</filename>. There's nothing <emphasis>wrong</emphasis> with this, but if you prefer to be consistent, you can change this by copying over the sample configuration file:</para>
+                            <programlisting language="Bash">
+cd /etc/cloudstack/agent
+mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml
+service cloudstack-agent restart
+                            </programlisting>
+                        </listitem>
+                        <listitem>
+                            <para>Once the agent is running, you can uninstall the old cloud-* packages from your system:</para>
+                            <programlisting language="Bash">sudo dpkg --purge cloud-agent</programlisting>
+                        </listitem> 
+                    </orderedlist>
                 </listitem>
-                <listitem>
+                <listitem id="upgrade-rpm-packages-302">
+                    <para>If you are using CentOS or RHEL, follow this procedure to upgrade your packages. If not, skip to step <xref linkend="correct-components-xml-302" />.</para> 
+                    <note><title>Community Packages</title>
+                        <para>This section assumes you're using the community supplied packages for &PRODUCT;. If you've created your own packages and yum repository, substitute your own URL for the ones used in these examples.</para>
+                    </note>
+                    <orderedlist id="rpmsteps-302">
+                        <listitem>
+                            <para>The first order of business will be to change the yum repository for each system with &PRODUCT; packages. This means all management servers, and any hosts that have the KVM agent. (No changes should be necessary for hosts that are running VMware or Xen.)</para>
+                            <para>Start by opening <filename>/etc/yum.repos.d/cloudstack.repo</filename> on any systems that have &PRODUCT; packages installed.</para>
+                            <para>This file should have content similar to the following:</para>
+                            <programlisting language="Bash">
+[apache-cloudstack]
+name=Apache CloudStack
+baseurl=http://cloudstack.apt-get.eu/rhel/4.0/
+enabled=1
+gpgcheck=0
+                            </programlisting>
+                            <para>If you are using the community provided package repository, change the baseurl to http://cloudstack.apt-get.eu/rhel/4.1/</para>
+                            <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
+                        </listitem>
+                        <listitem id="rpm-master-302">
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package. This will pull in any other dependencies you need.</para>
+                            <programlisting language="Bash">$ sudo yum install cloudstack-management</programlisting>
+                        </listitem>
+                        <listitem id="kvm-agent-rpm-302">
+                            <para>For KVM hosts, you will need to upgrade the <filename>cloudstack-agent</filename> package:</para>
+                            <programlisting language="Bash">$ sudo yum install cloudstack-agent</programlisting>
+                            <para>During the installation of <filename>cloudstack-agent</filename>, the RPM will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Verify that the file <filename>/etc/cloudstack/agent/environment.properties</filename> has a line that reads:</para>
+                            <programlisting language="Bash">paths.script=/usr/share/cloudstack-common</programlisting>
+                            <para>If not, add the line.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Restart the agent:</para>
+                            <programlisting language="Bash">
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
+                            </programlisting>
+                        </listitem>
+                    </orderedlist>
+                </listitem>
+                <listitem id="correct-components-xml-302">
                     <para>If you have made changes to your copy of
                         <filename>/etc/cloud/management/components.xml</filename> the changes will be
                         preserved in the upgrade. However, you need to do the following steps to place these


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

Posted by ts...@apache.org.
Modifying some extra tabs that cause rendering silliness in the release notes

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 7023920d3459516e07ae674bf0d1eb2ebcb99b2c
Parents: 34899f9
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 12:06:50 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 12:28:09 2013 -0400

----------------------------------------------------------------------
 docs/en-US/Release_Notes.xml |   30 +++++++++++++++---------------
 1 files changed, 15 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7023920d/docs/en-US/Release_Notes.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml
index d51e9fb..09cf2e2 100644
--- a/docs/en-US/Release_Notes.xml
+++ b/docs/en-US/Release_Notes.xml
@@ -4181,17 +4181,17 @@ under the License.
                         <listitem>
                             <para>Restart the agent:</para>
                             <programlisting language="Bash">
-                                service cloud-agent stop
-                                killall jsvc
-                                service cloudstack-agent start
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
                             </programlisting>
                         </listitem>
                         <listitem>
                             <para>During the upgrade, <filename>log4j-cloud.xml</filename> was simply copied over, so the logs will continue to be added to <filename>/var/log/cloud/agent/agent.log</filename>. There's nothing <emphasis>wrong</emphasis> with this, but if you prefer to be consistent, you can change this by copying over the sample configuration file:</para>
                             <programlisting language="Bash">
-                                cd /etc/cloudstack/agent
-                                mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml
-                                service cloudstack-agent restart
+cd /etc/cloudstack/agent
+mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml
+service cloudstack-agent restart
                             </programlisting>
                         </listitem>
                         <listitem>
@@ -4237,9 +4237,9 @@ gpgcheck=0
                         <listitem>
                             <para>Restart the agent:</para>
                             <programlisting language="Bash">
-                                service cloud-agent stop
-                                killall jsvc
-                                service cloudstack-agent start
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
                             </programlisting>
                         </listitem>
                     </orderedlist>
@@ -4252,12 +4252,12 @@ gpgcheck=0
                     <programlisting language="Bash"><prompt>#</prompt> tail -f sysvm.log</programlisting>
                     <para>The output to <filename>sysvm.log</filename> will look something like this:</para>
                     <programlisting language="Bash">
-                        Stopping and starting 1 secondary storage vm(s)...
-                        Done stopping and starting secondary storage vm(s)
-                        Stopping and starting 1 console proxy vm(s)...
-                        Done stopping and starting console proxy vm(s).
-                        Stopping and starting 4 running routing vm(s)...
-                        Done restarting router(s).
+Stopping and starting 1 secondary storage vm(s)...
+Done stopping and starting secondary storage vm(s)
+Stopping and starting 1 console proxy vm(s)...
+Done stopping and starting console proxy vm(s).
+Stopping and starting 4 running routing vm(s)...
+Done restarting router(s).
                     </programlisting>
                 </listitem>
                 <listitem>


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

Posted by ts...@apache.org.
decode the response as first class python object

createAccountResponse is now an instance of createAccountResponse and
not just a plain dict.

TODO:
1. nested entities don't work yet.

Signed-off-by: Prasanna Santhanam <ts...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: da464aaf90eba20d7081b824b3a2233beeddd75a
Parents: 3814eb3
Author: Prasanna Santhanam <ts...@apache.org>
Authored: Fri Apr 19 16:52:44 2013 +0530
Committer: Prasanna Santhanam <ts...@apache.org>
Committed: Fri Apr 19 16:52:44 2013 +0530

----------------------------------------------------------------------
 tools/marvin/marvin/cloudstackConnection.py |    6 +++---
 tools/marvin/marvin/jsonHelper.py           |    3 ++-
 2 files changed, 5 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/da464aaf/tools/marvin/marvin/cloudstackConnection.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py
index b1d5a51..f6589bb 100644
--- a/tools/marvin/marvin/cloudstackConnection.py
+++ b/tools/marvin/marvin/cloudstackConnection.py
@@ -21,9 +21,9 @@ import base64
 import hmac
 import hashlib
 import time
-import marvin.cloudstackException
+from marvin import cloudstackException
 from marvin.cloudstackAPI import *
-import marvin.jsonHelper
+from marvin import jsonHelper
 from requests import ConnectionError
 from requests import HTTPError
 from requests import Timeout
@@ -137,7 +137,7 @@ class CloudConnection(object):
             else:
                 response = requests.get(self.baseurl, params=payload)
         except ConnectionError, c:
-            self.logging.debug("Connection refused. Reason: %s" %
+            self.logging.debug("Connection refused. Reason: %s %s" %
                                (self.baseurl, c))
             raise c
         except HTTPError, h:

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/da464aaf/tools/marvin/marvin/jsonHelper.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/jsonHelper.py b/tools/marvin/marvin/jsonHelper.py
index 5b492b1..b0c356f 100644
--- a/tools/marvin/marvin/jsonHelper.py
+++ b/tools/marvin/marvin/jsonHelper.py
@@ -102,7 +102,8 @@ def finalizeResultObj(result, responseName, responsecls):
                 mirrorObj = False
                 break
         if mirrorObj:
-            return value
+            responsecls.__dict__.update(value.__dict__)
+            return responsecls
         else:
             return result
     else:


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

Posted by ts...@apache.org.
CLOUDSTACK-1343: cloudstack UI - baremetal - zone wizard - fix a JS error "args.data.cluster is undefined" that happened right after Configuring guest traffic.


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

Branch: refs/heads/marvin_refactor
Commit: 320cad3806ec091d604779695979b1b34f671873
Parents: 73d87f1
Author: Jessica Wang <je...@citrix.com>
Authored: Thu Apr 18 14:28:28 2013 -0700
Committer: Jessica Wang <je...@citrix.com>
Committed: Thu Apr 18 14:29:00 2013 -0700

----------------------------------------------------------------------
 ui/scripts/zoneWizard.js |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/320cad38/ui/scripts/zoneWizard.js
----------------------------------------------------------------------
diff --git a/ui/scripts/zoneWizard.js b/ui/scripts/zoneWizard.js
index 08cadd0..6299fab 100755
--- a/ui/scripts/zoneWizard.js
+++ b/ui/scripts/zoneWizard.js
@@ -3053,7 +3053,7 @@
                 args.data.returnedGuestNetwork.returnedVlanIpRange = json.createvlaniprangeresponse.vlan;
                 
 								//when hypervisor is BareMetal (begin)   						
-								if(args.data.cluster.hypervisor == "BareMetal") {
+								if(args.data.zone.hypervisor == "BareMetal") {
 								  alert('Zone creation is completed. Please refresh this page.');
 								}								
 								else {


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

Posted by ts...@apache.org.
CLOUDSTACK-2033 Fix usage server logging under Debian and Ubuntu


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

Branch: refs/heads/marvin_refactor
Commit: 96cf79535fb68881d7d191109ffa6d8f504e3136
Parents: dfbe113
Author: Wido den Hollander <wi...@42on.com>
Authored: Thu Apr 18 10:26:09 2013 +0200
Committer: Wido den Hollander <wi...@42on.com>
Committed: Thu Apr 18 10:26:09 2013 +0200

----------------------------------------------------------------------
 packaging/debian/replace.properties |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/96cf7953/packaging/debian/replace.properties
----------------------------------------------------------------------
diff --git a/packaging/debian/replace.properties b/packaging/debian/replace.properties
index 8c85206..5a0bd58 100644
--- a/packaging/debian/replace.properties
+++ b/packaging/debian/replace.properties
@@ -57,6 +57,6 @@ SYSCONFDIR=/etc
 SYSTEMCLASSPATH=
 SYSTEMJARS=
 USAGECLASSPATH=
-USAGELOG=/var/log/cloudstack/usage
+USAGELOG=/var/log/cloudstack/usage/usage.log
 USAGESYSCONFDIR=/etc/cloudstack/usage
 PACKAGE=cloudstack


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

Posted by ts...@apache.org.
Removing 'incubator' from the default source dir

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: ce8c2eb8a59922ed83e08296b25591c43dac03e6
Parents: fca7b3e
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 14:52:45 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 14:54:42 2013 -0400

----------------------------------------------------------------------
 tools/build/build_asf.sh |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/ce8c2eb8/tools/build/build_asf.sh
----------------------------------------------------------------------
diff --git a/tools/build/build_asf.sh b/tools/build/build_asf.sh
index c692feb..f58f5e0 100755
--- a/tools/build/build_asf.sh
+++ b/tools/build/build_asf.sh
@@ -17,7 +17,7 @@
 # under the License.
 
 version='TESTBUILD'
-sourcedir=~/incubator-cloudstack/
+sourcedir=~/cloudstack/
 outputdir=~/cs-asf-build/
 branch='master'
 tag='no'


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

Posted by ts...@apache.org.
ClOUDSTACK-2111:UI remain in processing state even after scaleVM executed successfullY


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

Branch: refs/heads/marvin_refactor
Commit: f98ce5ddccac4bab4c543d9ba01d817e4bec9eda
Parents: ea893ea
Author: Pranav Saxena <pr...@citrix.com>
Authored: Fri Apr 19 15:14:57 2013 +0530
Committer: Pranav Saxena <pr...@citrix.com>
Committed: Fri Apr 19 15:14:57 2013 +0530

----------------------------------------------------------------------
 ui/scripts/instances.js |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/f98ce5dd/ui/scripts/instances.js
----------------------------------------------------------------------
diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js
index 21b58ae..b2d9dde 100644
--- a/ui/scripts/instances.js
+++ b/ui/scripts/instances.js
@@ -1115,7 +1115,7 @@
                 dataType: "json",
                 async: true,
                 success: function(json) {
-                  var jid = json.scaleupvirtualmachineresponse.jobid;
+                  var jid = json.scalevirtualmachineresponse.jobid;
                   args.response.success(
                     {_custom:
                      {jobId: jid,


[26/35] 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 c

Posted by ts...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java
index 1adff40..7796529 100644
--- a/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/HostJoinDaoImpl.java
@@ -29,6 +29,7 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.api.ApiConstants.HostDetails;
 import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.cloudstack.api.response.HostForMigrationResponse;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -190,10 +191,6 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
     }
 
 
-
-
-
-
     @Override
     public HostResponse setHostResponse(HostResponse response, HostJoinVO host) {
         String tag = host.getTag();
@@ -208,7 +205,137 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
         return response;
     }
 
+    @Override
+    public HostForMigrationResponse newHostForMigrationResponse(HostJoinVO host, EnumSet<HostDetails> details) {
+        HostForMigrationResponse hostResponse = new HostForMigrationResponse();
+        hostResponse.setId(host.getUuid());
+        hostResponse.setCapabilities(host.getCapabilities());
+        hostResponse.setClusterId(host.getClusterUuid());
+        hostResponse.setCpuNumber(host.getCpus());
+        hostResponse.setZoneId(host.getZoneUuid());
+        hostResponse.setDisconnectedOn(host.getDisconnectedOn());
+        hostResponse.setHypervisor(host.getHypervisorType());
+        hostResponse.setHostType(host.getType());
+        hostResponse.setLastPinged(new Date(host.getLastPinged()));
+        hostResponse.setManagementServerId(host.getManagementServerId());
+        hostResponse.setName(host.getName());
+        hostResponse.setPodId(host.getPodUuid());
+        hostResponse.setRemoved(host.getRemoved());
+        hostResponse.setCpuSpeed(host.getSpeed());
+        hostResponse.setState(host.getStatus());
+        hostResponse.setIpAddress(host.getPrivateIpAddress());
+        hostResponse.setVersion(host.getVersion());
+        hostResponse.setCreated(host.getCreated());
+
+        if (details.contains(HostDetails.all) || details.contains(HostDetails.capacity)
+                || details.contains(HostDetails.stats) || details.contains(HostDetails.events)) {
 
+            hostResponse.setOsCategoryId(host.getOsCategoryUuid());
+            hostResponse.setOsCategoryName(host.getOsCategoryName());
+            hostResponse.setZoneName(host.getZoneName());
+            hostResponse.setPodName(host.getPodName());
+            if ( host.getClusterId() > 0) {
+                hostResponse.setClusterName(host.getClusterName());
+                hostResponse.setClusterType(host.getClusterType().toString());
+            }
+        }
+
+        DecimalFormat decimalFormat = new DecimalFormat("#.##");
+        if (host.getType() == Host.Type.Routing) {
+            if (details.contains(HostDetails.all) || details.contains(HostDetails.capacity)) {
+                // set allocated capacities
+                Long mem = host.getMemReservedCapacity() + host.getMemUsedCapacity();
+                Long cpu = host.getCpuReservedCapacity() + host.getCpuReservedCapacity();
+
+                hostResponse.setMemoryAllocated(mem);
+                hostResponse.setMemoryTotal(host.getTotalMemory());
+
+                String hostTags = host.getTag();
+                hostResponse.setHostTags(host.getTag());
+
+                String haTag = ApiDBUtils.getHaTag();
+                if (haTag != null && !haTag.isEmpty() && hostTags != null && !hostTags.isEmpty()) {
+                    if (haTag.equalsIgnoreCase(hostTags)) {
+                        hostResponse.setHaHost(true);
+                    } else {
+                        hostResponse.setHaHost(false);
+                    }
+                } else {
+                    hostResponse.setHaHost(false);
+                }
+
+                hostResponse.setHypervisorVersion(host.getHypervisorVersion());
+
+                String cpuAlloc = decimalFormat.format(((float) cpu / (float) (host.getCpus() * host.getSpeed())) * 100f) + "%";
+                hostResponse.setCpuAllocated(cpuAlloc);
+                String cpuWithOverprovisioning = new Float(host.getCpus() * host.getSpeed() * ApiDBUtils.getCpuOverprovisioningFactor()).toString();
+                hostResponse.setCpuWithOverprovisioning(cpuWithOverprovisioning);
+            }
+
+            if (details.contains(HostDetails.all) || details.contains(HostDetails.stats)) {
+                // set CPU/RAM/Network stats
+                String cpuUsed = null;
+                HostStats hostStats = ApiDBUtils.getHostStatistics(host.getId());
+                if (hostStats != null) {
+                    float cpuUtil = (float) hostStats.getCpuUtilization();
+                    cpuUsed = decimalFormat.format(cpuUtil) + "%";
+                    hostResponse.setCpuUsed(cpuUsed);
+                    hostResponse.setMemoryUsed((new Double(hostStats.getUsedMemory())).longValue());
+                    hostResponse.setNetworkKbsRead((new Double(hostStats.getNetworkReadKBs())).longValue());
+                    hostResponse.setNetworkKbsWrite((new Double(hostStats.getNetworkWriteKBs())).longValue());
+
+                }
+            }
+
+        } else if (host.getType() == Host.Type.SecondaryStorage) {
+            StorageStats secStorageStats = ApiDBUtils.getSecondaryStorageStatistics(host.getId());
+            if (secStorageStats != null) {
+                hostResponse.setDiskSizeTotal(secStorageStats.getCapacityBytes());
+                hostResponse.setDiskSizeAllocated(secStorageStats.getByteUsed());
+            }
+        }
+
+        hostResponse.setLocalStorageActive(ApiDBUtils.isLocalStorageActiveOnHost(host.getId()));
+
+        if (details.contains(HostDetails.all) || details.contains(HostDetails.events)) {
+            Set<com.cloud.host.Status.Event> possibleEvents = host.getStatus().getPossibleEvents();
+            if ((possibleEvents != null) && !possibleEvents.isEmpty()) {
+                String events = "";
+                Iterator<com.cloud.host.Status.Event> iter = possibleEvents.iterator();
+                while (iter.hasNext()) {
+                    com.cloud.host.Status.Event event = iter.next();
+                    events += event.toString();
+                    if (iter.hasNext()) {
+                        events += "; ";
+                    }
+                }
+                hostResponse.setEvents(events);
+            }
+        }
+
+        hostResponse.setResourceState(host.getResourceState().toString());
+
+        // set async job
+        hostResponse.setJobId(host.getJobUuid());
+        hostResponse.setJobStatus(host.getJobStatus());
+
+        hostResponse.setObjectName("host");
+
+        return hostResponse;
+    }
+
+    @Override
+    public HostForMigrationResponse setHostForMigrationResponse(HostForMigrationResponse response, HostJoinVO host) {
+        String tag = host.getTag();
+        if (tag != null) {
+            if (response.getHostTags() != null && response.getHostTags().length() > 0) {
+                response.setHostTags(response.getHostTags() + "," + tag);
+            } else {
+                response.setHostTags(tag);
+            }
+        }
+        return response;
+    }
 
     @Override
     public List<HostJoinVO> newHostView(Host host) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/dao/StoragePoolJoinDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/StoragePoolJoinDao.java b/server/src/com/cloud/api/query/dao/StoragePoolJoinDao.java
index bbb0242..b7e467f 100644
--- a/server/src/com/cloud/api/query/dao/StoragePoolJoinDao.java
+++ b/server/src/com/cloud/api/query/dao/StoragePoolJoinDao.java
@@ -18,6 +18,7 @@ package com.cloud.api.query.dao;
 
 import java.util.List;
 
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 
 import com.cloud.api.query.vo.StoragePoolJoinVO;
@@ -30,6 +31,11 @@ public interface StoragePoolJoinDao extends GenericDao<StoragePoolJoinVO, Long>
 
     StoragePoolResponse setStoragePoolResponse(StoragePoolResponse response, StoragePoolJoinVO host);
 
+    StoragePoolForMigrationResponse newStoragePoolForMigrationResponse(StoragePoolJoinVO host);
+
+    StoragePoolForMigrationResponse setStoragePoolForMigrationResponse(StoragePoolForMigrationResponse response,
+            StoragePoolJoinVO host);
+
     List<StoragePoolJoinVO> newStoragePoolView(StoragePool group);
 
     List<StoragePoolJoinVO> searchByIds(Long... spIds);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
index 58968df..34b88ba 100644
--- a/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/StoragePoolJoinDaoImpl.java
@@ -22,6 +22,7 @@ import java.util.List;
 import javax.ejb.Local;
 import javax.inject.Inject;
 
+import org.apache.cloudstack.api.response.StoragePoolForMigrationResponse;
 import org.apache.cloudstack.api.response.StoragePoolResponse;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
@@ -108,10 +109,6 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
         return poolResponse;
     }
 
-
-
-
-
     @Override
     public StoragePoolResponse setStoragePoolResponse(StoragePoolResponse response, StoragePoolJoinVO sp) {
         String tag = sp.getTag();
@@ -126,7 +123,61 @@ public class StoragePoolJoinDaoImpl extends GenericDaoBase<StoragePoolJoinVO, Lo
         return response;
     }
 
+    @Override
+    public StoragePoolForMigrationResponse newStoragePoolForMigrationResponse(StoragePoolJoinVO pool) {
+        StoragePoolForMigrationResponse poolResponse = new StoragePoolForMigrationResponse();
+        poolResponse.setId(pool.getUuid());
+        poolResponse.setName(pool.getName());
+        poolResponse.setState(pool.getStatus());
+        poolResponse.setPath(pool.getPath());
+        poolResponse.setIpAddress(pool.getHostAddress());
+        poolResponse.setZoneId(pool.getZoneUuid());
+        poolResponse.setZoneName(pool.getZoneName());
+        if (pool.getPoolType() != null) {
+            poolResponse.setType(pool.getPoolType().toString());
+        }
+        poolResponse.setPodId(pool.getPodUuid());
+        poolResponse.setPodName(pool.getPodName());
+        poolResponse.setCreated(pool.getCreated());
+        poolResponse.setScope(pool.getScope().toString());
+
 
+        long allocatedSize = pool.getUsedCapacity() +  pool.getReservedCapacity();
+        poolResponse.setDiskSizeTotal(pool.getCapacityBytes());
+        poolResponse.setDiskSizeAllocated(allocatedSize);
+
+        //TODO: StatsCollector does not persist data
+        StorageStats stats = ApiDBUtils.getStoragePoolStatistics(pool.getId());
+        if (stats != null) {
+            Long used = stats.getByteUsed();
+            poolResponse.setDiskSizeUsed(used);
+        }
+
+        poolResponse.setClusterId(pool.getClusterUuid());
+        poolResponse.setClusterName(pool.getClusterName());
+        poolResponse.setTags(pool.getTag());
+
+        // set async job
+        poolResponse.setJobId(pool.getJobUuid());
+        poolResponse.setJobStatus(pool.getJobStatus());
+
+        poolResponse.setObjectName("storagepool");
+        return poolResponse;
+    }
+
+    @Override
+    public StoragePoolForMigrationResponse setStoragePoolForMigrationResponse(StoragePoolForMigrationResponse response,
+            StoragePoolJoinVO sp) {
+        String tag = sp.getTag();
+        if (tag != null) {
+            if ( response.getTags() != null && response.getTags().length() > 0){
+                response.setTags(response.getTags() + "," + tag);
+            } else {
+                response.setTags(tag);
+            }
+        }
+        return response;
+    }
 
     @Override
     public List<StoragePoolJoinVO> newStoragePoolView(StoragePool host) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index db8db8a..16127a2 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -214,6 +214,7 @@ import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
 import org.apache.cloudstack.api.command.admin.vlan.ListVlanIpRangesCmd;
 import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd;
 import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd;
+import org.apache.cloudstack.api.command.admin.vm.MigrateVirtualMachineWithVolumeCmd;
 import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd;
 import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd;
 import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
@@ -256,6 +257,7 @@ import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
 import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToSnapshotCmd;
 import org.apache.cloudstack.api.command.user.zone.ListZonesByCmd;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 
@@ -329,6 +331,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     @Inject
     private StorageManager _storageMgr;
     @Inject
+    private VolumeManager _volumeMgr;
+    @Inject
     private VirtualMachineManager _itMgr;
     @Inject
     private HostPodDao _hostPodDao;
@@ -352,10 +356,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     private LoadBalancerDao _loadbalancerDao;
     @Inject
     private HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
-
     private List<HostAllocator> _hostAllocators;
-
-	@Inject
+    @Inject
+    private List<StoragePoolAllocator> _storagePoolAllocators;
+    @Inject
     private ConfigurationManager _configMgr;
     @Inject
     private ResourceTagDao _resourceTagDao;
@@ -679,12 +683,14 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         Object resourceState = cmd.getResourceState();
         Object haHosts = cmd.getHaHost();
 
-        Pair<List<HostVO>, Integer> result = searchForServers(cmd.getStartIndex(), cmd.getPageSizeVal(), name, type, state, zoneId, pod, cluster, id, keyword, resourceState, haHosts);
+        Pair<List<HostVO>, Integer> result = searchForServers(cmd.getStartIndex(), cmd.getPageSizeVal(), name, type,
+                state, zoneId, pod, cluster, id, keyword, resourceState, haHosts, null, null);
         return new Pair<List<? extends Host>, Integer>(result.first(), result.second());
     }
 
     @Override
-    public Pair<Pair<List<? extends Host>, Integer>, List<? extends Host>> listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize) {
+    public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>>
+            listHostsForMigrationOfVM(Long vmId, Long startIndex, Long pageSize) {
         // access check - only root admin can migrate VM
         Account caller = UserContext.current().getCaller();
         if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
@@ -700,12 +706,13 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
             ex.addProxyObject(vm, vmId, "vmId");
             throw ex;
         }
-        // business logic
+
         if (vm.getState() != State.Running) {
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug("VM is not Running, unable to migrate the vm" + vm);
             }
-            InvalidParameterValueException ex = new InvalidParameterValueException("VM is not Running, unable to migrate the vm with specified id");
+            InvalidParameterValueException ex = new InvalidParameterValueException("VM is not Running, unable to" +
+                    " migrate the vm with specified id");
             ex.addProxyObject(vm, vmId, "vmId");
             throw ex;
         }
@@ -715,17 +722,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
             if (s_logger.isDebugEnabled()) {
                 s_logger.debug(vm + " is not XenServer/VMware/KVM/OVM, cannot migrate this VM.");
             }
-            throw new InvalidParameterValueException("Unsupported Hypervisor Type for VM migration, we support XenServer/VMware/KVM only");
-        }
-        ServiceOfferingVO svcOffering = _offeringsDao.findById(vm.getServiceOfferingId());
-        if (svcOffering.getUseLocalStorage()) {
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug(vm + " is using Local Storage, cannot migrate this VM.");
-            }
-            throw new InvalidParameterValueException("Unsupported operation, VM uses Local storage, cannot migrate");
+            throw new InvalidParameterValueException("Unsupported Hypervisor Type for VM migration, we support " +
+                    "XenServer/VMware/KVM/Ovm only");
         }
+
         long srcHostId = vm.getHostId();
-        // why is this not HostVO?
         Host srcHost = _hostDao.findById(srcHostId);
         if (srcHost == null) {
             if (s_logger.isDebugEnabled()) {
@@ -737,32 +738,73 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
             ex.addProxyObject(vm, vmId, "vmId");
             throw ex;
         }
-        Long cluster = srcHost.getClusterId();
-        Type hostType = srcHost.getType();
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Searching for all hosts in cluster: " + cluster + " for migrating VM " + vm);
-        }
-
-        Pair<List<HostVO>, Integer> allHostsInClusterPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, null, null, null);
 
-        // filter out the current host
-        List<HostVO> allHostsInCluster = allHostsInClusterPair.first();
-        allHostsInCluster.remove(srcHost);
-        Pair<List<? extends Host>, Integer> otherHostsInCluster = new Pair<List <? extends Host>, Integer>(allHostsInCluster, new Integer(allHostsInClusterPair.second().intValue()-1));
+        // Check if the vm can be migrated with storage.
+        boolean canMigrateWithStorage = false;
+        HypervisorCapabilitiesVO capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(
+                srcHost.getHypervisorType(), srcHost.getHypervisorVersion());
+        if (capabilities != null) {
+            canMigrateWithStorage = capabilities.isStorageMotionSupported();
+        }
 
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Other Hosts in this cluster: " + allHostsInCluster);
+        // Check if the vm is using any disks on local storage.
+        VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
+        List<VolumeVO> volumes = _volumeDao.findCreatedByInstance(vmProfile.getId());
+        boolean usesLocal = false;
+        for (VolumeVO volume : volumes) {
+            DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+            DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType());
+            if (diskProfile.useLocalStorage()) {
+                usesLocal = true;
+                break;
+            }
         }
 
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Calling HostAllocators to search for hosts in cluster: " + cluster + " having enough capacity and suitable for migration");
+        if (!canMigrateWithStorage && usesLocal) {
+            throw new InvalidParameterValueException("Unsupported operation, VM uses Local storage, cannot migrate");
         }
 
-        List<Host> suitableHosts = new ArrayList<Host>();
+        Type hostType = srcHost.getType();
+        Pair<List<HostVO>, Integer> allHostsPair = null;
+        List<HostVO> allHosts = null;
+        Map<Host, Boolean> requiresStorageMotion = new HashMap<Host, Boolean>();
+        DataCenterDeployment plan = null;
+        if (canMigrateWithStorage) {
+            allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null,
+                    null, null, null, null, null, srcHost.getHypervisorType(), srcHost.getHypervisorVersion());
+            allHosts = allHostsPair.first();
+            allHosts.remove(srcHost);
+
+            // Check if the host has storage pools for all the volumes of the vm to be migrated.
+            for (Host host : allHosts) {
+                Map<Volume, List<StoragePool>> volumePools = findSuitablePoolsForVolumes(vmProfile, host);
+                if (volumePools.isEmpty()) {
+                    allHosts.remove(host);
+                } else {
+                    if (host.getClusterId() != srcHost.getClusterId() || usesLocal) {
+                        requiresStorageMotion.put(host, true);
+                    }
+                }
+            }
 
-        VirtualMachineProfile<VMInstanceVO> vmProfile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
+            plan = new DataCenterDeployment(srcHost.getDataCenterId(), null, null, null, null, null);
+        } else {
+            Long cluster = srcHost.getClusterId();
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Searching for all hosts in cluster " + cluster + " for migrating VM " + vm);
+            }
+            allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, null, null, cluster, null, null,
+                    null, null, null, null);
+            // Filter out the current host.
+            allHosts = allHostsPair.first();
+            allHosts.remove(srcHost);
+            plan = new DataCenterDeployment(srcHost.getDataCenterId(), srcHost.getPodId(), srcHost.getClusterId(),
+                    null, null, null);
+        }
 
-        DataCenterDeployment plan = new DataCenterDeployment(srcHost.getDataCenterId(), srcHost.getPodId(), srcHost.getClusterId(), null, null, null);
+        Pair<List<? extends Host>, Integer> otherHosts = new Pair<List <? extends Host>, Integer>(allHosts,
+                new Integer(allHosts.size()));
+        List<Host> suitableHosts = new ArrayList<Host>();
         ExcludeList excludes = new ExcludeList();
         excludes.addHost(srcHostId);
 
@@ -776,25 +818,174 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         }
 
         for (HostAllocator allocator : _hostAllocators) {
-            suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, HostAllocator.RETURN_UPTO_ALL, false);
+            if  (canMigrateWithStorage) {
+                suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes, allHosts,
+                        HostAllocator.RETURN_UPTO_ALL, false);
+            } else {
+                suitableHosts = allocator.allocateTo(vmProfile, plan, Host.Type.Routing, excludes,
+                        HostAllocator.RETURN_UPTO_ALL, false);
+            }
+
             if (suitableHosts != null && !suitableHosts.isEmpty()) {
                 break;
             }
         }
 
-        if (suitableHosts.isEmpty()) {
-            s_logger.debug("No suitable hosts found");
-        } else {
-            if (s_logger.isDebugEnabled()) {
+        if (s_logger.isDebugEnabled()) {
+            if (suitableHosts.isEmpty()) {
+                s_logger.debug("No suitable hosts found");
+            } else {
                 s_logger.debug("Hosts having capacity and suitable for migration: " + suitableHosts);
             }
         }
 
-        return new Pair<Pair<List<? extends Host>, Integer>, List<? extends Host>>(otherHostsInCluster, suitableHosts);
+        return new Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> (otherHosts,
+                suitableHosts, requiresStorageMotion);
+    }
+
+    private Map<Volume, List<StoragePool>> findSuitablePoolsForVolumes(VirtualMachineProfile<VMInstanceVO> vmProfile,
+            Host host) {
+        List<VolumeVO> volumes = _volumeDao.findCreatedByInstance(vmProfile.getId());
+        Map<Volume, List<StoragePool>> suitableVolumeStoragePools = new HashMap<Volume, List<StoragePool>>();
+
+        // For each volume find list of suitable storage pools by calling the allocators
+        for (VolumeVO volume : volumes) {
+            DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+            DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType());
+            DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(),
+                    host.getClusterId(), host.getId(), null, null);
+            ExcludeList avoid = new ExcludeList();
+
+            boolean foundPools = false;
+            for (StoragePoolAllocator allocator : _storagePoolAllocators) {
+                List<StoragePool> poolList = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid,
+                        StoragePoolAllocator.RETURN_UPTO_ALL);
+                if (poolList != null && !poolList.isEmpty()) {
+                    suitableVolumeStoragePools.put(volume, poolList);
+                    foundPools = true;
+                    break;
+                }
+            }
+
+            if (!foundPools) {
+                suitableVolumeStoragePools.clear();
+                break;
+            }
+        }
+
+        return suitableVolumeStoragePools;
+    }
+
+    @Override
+    public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStoragePoolsForMigrationOfVolume(Long volumeId) {
+        // Access check - only root administrator can migrate volumes.
+        Account caller = UserContext.current().getCaller();
+        if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Caller is not a root admin, permission denied to migrate the volume");
+            }
+            throw new PermissionDeniedException("No permission to migrate volume, only root admin can migrate a volume");
+        }
+
+        VolumeVO volume = _volumeDao.findById(volumeId);
+        if (volume == null) {
+            InvalidParameterValueException ex = new InvalidParameterValueException("Unable to find volume with" +
+                    " specified id.");
+            ex.addProxyObject(volume, volumeId, "volumeId");
+            throw ex;
+        }
+
+        // Volume must be attached to an instance for live migration.
+        List<StoragePool> allPools = new ArrayList<StoragePool>();
+        List<StoragePool> suitablePools = new ArrayList<StoragePool>();
+        Long instanceId = volume.getInstanceId();
+        VMInstanceVO vm = null;
+        if (instanceId != null) {
+            vm = _vmInstanceDao.findById(instanceId);
+        }
+
+        // Check that the VM is in correct state.
+        if (vm == null || vm.getState() != State.Running) {
+            s_logger.info("Volume " + volume + " isn't attached to any running vm. Only volumes attached to a running" +
+                    " VM can be migrated.");
+            return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
+        }
+
+        // Volume must be in Ready state to be migrated.
+        if (!Volume.State.Ready.equals(volume.getState())) {
+            s_logger.info("Volume " + volume + " must be in ready state for migration.");
+            return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
+        }
+
+        if (!_volumeMgr.volumeOnSharedStoragePool(volume)) {
+            s_logger.info("Volume " + volume + " is on local storage. It cannot be migrated to another pool.");
+            return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
+        }
+
+        // Check if the underlying hypervisor supports storage motion.
+        boolean storageMotionSupported = false;
+        Long hostId = vm.getHostId();
+        if (hostId != null) {
+            HostVO host = _hostDao.findById(hostId);
+            HypervisorCapabilitiesVO capabilities = null;
+            if (host != null) {
+                capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(host.getHypervisorType(),
+                        host.getHypervisorVersion());
+            } else {
+                s_logger.error("Details of the host on which the vm " + vm + ", to which volume "+ volume + " is "
+                        + "attached, couldn't be retrieved.");
+            }
+
+            if (capabilities != null) {
+                storageMotionSupported = capabilities.isStorageMotionSupported();
+            } else {
+                s_logger.error("Capabilities for host " + host + " couldn't be retrieved.");
+            }
+        }
+
+        if (storageMotionSupported) {
+            // Source pool of the volume.
+            StoragePoolVO srcVolumePool = _poolDao.findById(volume.getPoolId());
+
+            // Get all the pools available. Only shared pools are considered because only a volume on a shared pools
+            // can be live migrated while the virtual machine stays on the same host.
+            List<StoragePoolVO> storagePools = _poolDao.findPoolsByTags(volume.getDataCenterId(),
+                    volume.getPodId(), srcVolumePool.getClusterId(), null);
+            storagePools.remove(srcVolumePool);
+            for (StoragePoolVO pool : storagePools) {
+                if (pool.isShared()) {
+                    allPools.add((StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()));
+                }
+            }
+
+            // Get all the suitable pools.
+            // Exclude the current pool from the list of pools to which the volume can be migrated.
+            ExcludeList avoid = new ExcludeList();
+            avoid.addPool(srcVolumePool.getId());
+
+            // Volume stays in the same cluster after migration.
+            DataCenterDeployment plan = new DataCenterDeployment(volume.getDataCenterId(), volume.getPodId(),
+                    srcVolumePool.getClusterId(), null, null, null);
+            VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
+
+            DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+            DiskProfile diskProfile = new DiskProfile(volume, diskOffering, profile.getHypervisorType());
+
+            // Call the storage pool allocator to find the list of storage pools.
+            for (StoragePoolAllocator allocator : _storagePoolAllocators) {
+                List<StoragePool> pools = allocator.allocateToPool(diskProfile, profile, plan, avoid,
+                        StoragePoolAllocator.RETURN_UPTO_ALL);
+                if (pools != null && !pools.isEmpty()) {
+                    suitablePools.addAll(pools);
+                    break;
+                }
+            }
+        }
+        return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
     }
 
     private Pair<List<HostVO>, Integer> searchForServers(Long startIndex, Long pageSize, Object name, Object type, Object state, Object zone, Object pod, Object cluster, Object id, Object keyword,
-            Object resourceState, Object haHosts) {
+            Object resourceState, Object haHosts, Object hypervisorType, Object hypervisorVersion) {
         Filter searchFilter = new Filter(HostVO.class, "id", Boolean.TRUE, startIndex, pageSize);
 
         SearchBuilder<HostVO> sb = _hostDao.createSearchBuilder();
@@ -806,6 +997,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ);
         sb.and("clusterId", sb.entity().getClusterId(), SearchCriteria.Op.EQ);
         sb.and("resourceState", sb.entity().getResourceState(), SearchCriteria.Op.EQ);
+        sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.EQ);
+        sb.and("hypervisorVersion", sb.entity().getHypervisorVersion(), SearchCriteria.Op.EQ);
 
         String haTag = _haMgr.getHaTag();
         SearchBuilder<HostTagVO> hostTagSearch = null;
@@ -855,6 +1048,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         if (cluster != null) {
             sc.setParameters("clusterId", cluster);
         }
+        if (hypervisorType != null) {
+            sc.setParameters("hypervisorType", hypervisorType);
+        }
+        if (hypervisorVersion != null) {
+            sc.setParameters("hypervisorVersion", hypervisorVersion);
+        }
 
         if (resourceState != null) {
             sc.setParameters("resourceState", resourceState);
@@ -1969,6 +2168,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(CancelMaintenanceCmd.class);
         cmdList.add(DeleteHostCmd.class);
         cmdList.add(ListHostsCmd.class);
+        cmdList.add(FindHostsForMigrationCmd.class);
         cmdList.add(PrepareForMaintenanceCmd.class);
         cmdList.add(ReconnectHostCmd.class);
         cmdList.add(UpdateHostCmd.class);
@@ -2025,6 +2225,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(DeletePoolCmd.class);
         cmdList.add(ListS3sCmd.class);
         cmdList.add(ListStoragePoolsCmd.class);
+        cmdList.add(FindStoragePoolsForMigrationCmd.class);
         cmdList.add(PreparePrimaryStorageForMaintenanceCmd.class);
         cmdList.add(UpdateStoragePoolCmd.class);
         cmdList.add(AddSwiftCmd.class);
@@ -2064,6 +2265,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(ReleasePublicIpRangeCmd.class);
         cmdList.add(AssignVMCmd.class);
         cmdList.add(MigrateVMCmd.class);
+        cmdList.add(MigrateVirtualMachineWithVolumeCmd.class);
         cmdList.add(RecoverVMCmd.class);
         cmdList.add(CreatePrivateGatewayCmd.class);
         cmdList.add(CreateVPCOfferingCmd.class);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/storage/VolumeManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java
index 2101038..d198e5d 100644
--- a/server/src/com/cloud/storage/VolumeManager.java
+++ b/server/src/com/cloud/storage/VolumeManager.java
@@ -18,6 +18,8 @@
  */
 package com.cloud.storage;
 
+import java.util.Map;
+
 import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
@@ -25,12 +27,15 @@ import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientStorageCapacityException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.Volume.Type;
 import com.cloud.user.Account;
@@ -80,6 +85,9 @@ public interface VolumeManager extends VolumeApiService {
 
     Volume migrateVolume(MigrateVolumeCmd cmd);
 
+    <T extends VMInstanceVO> void migrateVolumes(T vm, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            Map<VolumeVO, StoragePoolVO> volumeToPool);
+
     boolean storageMigration(
             VirtualMachineProfile<? extends VirtualMachine> vm,
             StoragePool destPool);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/storage/VolumeManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java
index 1e8edaf..e57d393 100644
--- a/server/src/com/cloud/storage/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/VolumeManagerImpl.java
@@ -28,6 +28,7 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.HashMap;
 import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ExecutionException;
@@ -42,6 +43,7 @@ import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
 import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
+import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
@@ -68,6 +70,7 @@ import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachVolumeAnswer;
 import com.cloud.agent.api.AttachVolumeCommand;
+import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.ApiDBUtils;
@@ -102,11 +105,13 @@ import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.StorageUnavailableException;
+import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.HypervisorGuruManager;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
+import com.cloud.hypervisor.HypervisorCapabilitiesVO;
 import com.cloud.network.NetworkModel;
 import com.cloud.org.Grouping;
 import com.cloud.resource.ResourceManager;
@@ -2003,7 +2008,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
     public Volume migrateVolume(MigrateVolumeCmd cmd) {
         Long volumeId = cmd.getVolumeId();
         Long storagePoolId = cmd.getStoragePoolId();
-        
+
         VolumeVO vol = _volsDao.findById(volumeId);
         if (vol == null) {
             throw new InvalidParameterValueException(
@@ -2015,9 +2020,39 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                     "Volume must be in ready state");
         }
 
-        if (vol.getInstanceId() != null) {
-            throw new InvalidParameterValueException(
-                    "Volume needs to be dettached from VM");
+        boolean liveMigrateVolume = false;
+        Long instanceId = vol.getInstanceId();
+        VMInstanceVO vm = null;
+        if (instanceId != null) {
+            vm = _vmInstanceDao.findById(instanceId);
+        }
+
+        if (vm != null && vm.getState() == State.Running) {
+            // Check if the underlying hypervisor supports storage motion.
+            Long hostId = vm.getHostId();
+            if (hostId != null) {
+                HostVO host = _hostDao.findById(hostId);
+                HypervisorCapabilitiesVO capabilities = null;
+                if (host != null) {
+                    capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(host.getHypervisorType(),
+                            host.getHypervisorVersion());
+                }
+
+                if (capabilities != null) {
+                    liveMigrateVolume = capabilities.isStorageMotionSupported();
+                }
+            }
+        }
+
+        // If the disk is not attached to any VM then it can be moved. Otherwise, it needs to be attached to a vm
+        // running on a hypervisor that supports storage motion so that it be be migrated.
+        if (instanceId != null && !liveMigrateVolume) {
+            throw new InvalidParameterValueException("Volume needs to be detached from VM");
+        }
+
+        if (liveMigrateVolume && !cmd.isLiveMigrate()) {
+            throw new InvalidParameterValueException("The volume " + vol + "is attached to a vm and for migrating it " +
+                    "the parameter livemigrate should be specified");
         }
 
         StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary);
@@ -2032,12 +2067,15 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                     "Migration of volume from local storage pool is not supported");
         }
 
-        Volume newVol = migrateVolume(vol, destPool);
+        Volume newVol = null;
+        if (liveMigrateVolume) {
+            newVol = liveMigrateVolume(vol, destPool);
+        } else {
+            newVol = migrateVolume(vol, destPool);
+        }
         return newVol;
     }
 
-    
-    
     @DB
     protected Volume migrateVolume(Volume volume, StoragePool destPool) {
         VolumeInfo vol = this.volFactory.getVolume(volume.getId());
@@ -2058,6 +2096,66 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         }
     }
 
+    @DB
+    protected Volume liveMigrateVolume(Volume volume, StoragePool destPool) {
+        VolumeInfo vol = this.volFactory.getVolume(volume.getId());
+        AsyncCallFuture<VolumeApiResult> future = this.volService.migrateVolume(vol, (DataStore)destPool);
+        try {
+            VolumeApiResult result = future.get();
+            if (result.isFailed()) {
+                s_logger.debug("migrate volume failed:" + result.getResult());
+                return null;
+            }
+            return result.getVolume();
+        } catch (InterruptedException e) {
+            s_logger.debug("migrate volume failed", e);
+            return null;
+        } catch (ExecutionException e) {
+            s_logger.debug("migrate volume failed", e);
+            return null;
+        }
+    }
+
+    @Override
+    public <T extends VMInstanceVO> void migrateVolumes(T vm, VirtualMachineTO vmTo, Host srcHost, Host destHost,
+            Map<VolumeVO, StoragePoolVO> volumeToPool) {
+        // Check if all the vms being migrated belong to the vm.
+        // Check if the storage pool is of the right type.
+        // Create a VolumeInfo to DataStore map too.
+        Map<VolumeInfo, DataStore> volumeMap = new HashMap<VolumeInfo, DataStore>();
+        for (Map.Entry<VolumeVO, StoragePoolVO> entry : volumeToPool.entrySet()) {
+            VolumeVO volume = entry.getKey();
+            StoragePoolVO storagePool = entry.getValue();
+            StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(storagePool.getId(),
+                    DataStoreRole.Primary);
+
+            if (volume.getInstanceId() != vm.getId()) {
+                throw new CloudRuntimeException("Volume " + volume + " that has to be migrated doesn't belong to the" +
+                        " instance " + vm);
+            }
+
+            if (destPool == null) {
+                throw new CloudRuntimeException("Failed to find the destination storage pool " + storagePool.getId());
+            }
+
+            volumeMap.put(this.volFactory.getVolume(volume.getId()), (DataStore)destPool);
+        }
+
+        AsyncCallFuture<CommandResult> future = this.volService.migrateVolumes(volumeMap, vmTo, srcHost, destHost);
+        try {
+            CommandResult result = future.get();
+            if (result.isFailed()) {
+                s_logger.debug("Failed to migrated vm " + vm + " along with its volumes. " + result.getResult());
+                throw new CloudRuntimeException("Failed to migrated vm " + vm + " along with its volumes. " +
+                        result.getResult());
+            }
+        } catch (InterruptedException e) {
+            s_logger.debug("Failed to migrated vm " + vm + " along with its volumes.", e);
+        } catch (ExecutionException e) {
+            s_logger.debug("Failed to migrated vm " + vm + " along with its volumes.", e);
+        }
+    }
+
     @Override
     public boolean storageMigration(
             VirtualMachineProfile<? extends VirtualMachine> vm,

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 3ecdf42..bc6237f 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -46,6 +46,7 @@ import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
 import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
 import org.apache.cloudstack.engine.service.api.OrchestrationService;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -108,6 +109,7 @@ import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.HypervisorCapabilitiesVO;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.network.Network;
 import com.cloud.network.Network.IpAddresses;
@@ -3502,6 +3504,127 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         return migratedVm;
     }
 
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VM_MIGRATE, eventDescription = "migrating VM", async = true)
+    public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost,
+            Map<String, String> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException,
+            ManagementServerException, VirtualMachineMigrationException {
+        // Access check - only root administrator can migrate VM.
+        Account caller = UserContext.current().getCaller();
+        if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("Caller is not a root admin, permission denied to migrate the VM");
+            }
+            throw new PermissionDeniedException("No permission to migrate VM, Only Root Admin can migrate a VM!");
+        }
+
+        VMInstanceVO vm = _vmInstanceDao.findById(vmId);
+        if (vm == null) {
+            throw new InvalidParameterValueException("Unable to find the vm by id " + vmId);
+        }
+
+        if (vm.getState() != State.Running) {
+            if (s_logger.isDebugEnabled()) {
+                s_logger.debug("VM is not Running, unable to migrate the vm " + vm);
+            }
+            CloudRuntimeException ex = new CloudRuntimeException("VM is not Running, unable to migrate the vm with" +
+                    " specified id");
+            ex.addProxyObject(vm, vmId, "vmId");
+            throw ex;
+        }
+
+        if (!vm.getHypervisorType().equals(HypervisorType.XenServer) &&
+                !vm.getHypervisorType().equals(HypervisorType.VMware) &&
+                !vm.getHypervisorType().equals(HypervisorType.KVM) &&
+                !vm.getHypervisorType().equals(HypervisorType.Ovm)) {
+            throw new InvalidParameterValueException("Unsupported hypervisor type for vm migration, we support" +
+                    " XenServer/VMware/KVM only");
+        }
+
+        long srcHostId = vm.getHostId();
+        Host srcHost = _resourceMgr.getHost(srcHostId);
+        // Check if src and destination hosts are valid and migrating to same host
+        if (destinationHost.getId() == srcHostId) {
+            throw new InvalidParameterValueException("Cannot migrate VM, VM is already present on this host, please" +
+                    " specify valid destination host to migrate the VM");
+        }
+
+        // Check if the source and destination hosts are of the same type and support storage motion.
+        if (!(srcHost.getHypervisorType().equals(destinationHost.getHypervisorType()) &&
+            srcHost.getHypervisorVersion().equals(destinationHost.getHypervisorVersion()))) {
+            throw new CloudRuntimeException("The source and destination hosts are not of the same type and version. " +
+                "Source hypervisor type and version: " + srcHost.getHypervisorType().toString() + " " +
+                srcHost.getHypervisorVersion() + ", Destination hypervisor type and version: " +
+                destinationHost.getHypervisorType().toString() + " " + destinationHost.getHypervisorVersion());
+        }
+
+        HypervisorCapabilitiesVO capabilities = _hypervisorCapabilitiesDao.findByHypervisorTypeAndVersion(
+                srcHost.getHypervisorType(), srcHost.getHypervisorVersion());
+        if (!capabilities.isStorageMotionSupported()) {
+            throw new CloudRuntimeException("Migration with storage isn't supported on hypervisor " +
+                    srcHost.getHypervisorType() + " of version " + srcHost.getHypervisorVersion());
+        }
+
+        // Check if destination host is up.
+        if (destinationHost.getStatus() != com.cloud.host.Status.Up ||
+                destinationHost.getResourceState() != ResourceState.Enabled){
+            throw new CloudRuntimeException("Cannot migrate VM, destination host is not in correct state, has " +
+                    "status: " + destinationHost.getStatus() + ", state: " + destinationHost.getResourceState());
+        }
+
+        List<VolumeVO> vmVolumes = _volsDao.findUsableVolumesForInstance(vm.getId());
+        Map<VolumeVO, StoragePoolVO> volToPoolObjectMap = new HashMap<VolumeVO, StoragePoolVO>();
+        if (!isVMUsingLocalStorage(vm) && destinationHost.getClusterId() == srcHost.getClusterId()) {
+            if (volumeToPool.isEmpty()) {
+                // If the destination host is in the same cluster and volumes do not have to be migrated across pools
+                // then fail the call. migrateVirtualMachine api should have been used.
+                throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost +
+                        " to destination host " + destinationHost + " doesn't involve migrating the volumes.");
+            }
+        }
+
+        if (!volumeToPool.isEmpty()) {
+            // Check if all the volumes and pools passed as parameters are valid.
+            for (Map.Entry<String, String> entry : volumeToPool.entrySet()) {
+                VolumeVO volume = _volsDao.findByUuid(entry.getKey());
+                StoragePoolVO pool = _storagePoolDao.findByUuid(entry.getValue());
+                if (volume == null) {
+                    throw new InvalidParameterValueException("There is no volume present with the given id " +
+                            entry.getKey());
+                } else if (pool == null) {
+                    throw new InvalidParameterValueException("There is no storage pool present with the given id " +
+                            entry.getValue());
+                } else {
+                    // Verify the volume given belongs to the vm.
+                    if (!vmVolumes.contains(volume)) {
+                        throw new InvalidParameterValueException("There volume " + volume + " doesn't belong to " +
+                                "the virtual machine "+ vm + " that has to be migrated");
+                    }
+                    volToPoolObjectMap.put(volume, pool);
+                }
+            }
+        }
+
+        // Check if all the volumes are in the correct state.
+        for (VolumeVO volume : vmVolumes) {
+            if (volume.getState() != Volume.State.Ready) {
+                throw new CloudRuntimeException("Volume " + volume + " of the VM is not in Ready state. Cannot " +
+                        "migrate the vm with its volumes.");
+            }
+        }
+
+        // Check max guest vm limit for the destinationHost.
+        HostVO destinationHostVO = _hostDao.findById(destinationHost.getId());
+        if(_capacityMgr.checkIfHostReachMaxGuestLimit(destinationHostVO)){
+            throw new VirtualMachineMigrationException("Host name: " + destinationHost.getName() + ", hostId: " +
+                    destinationHost.getId() + " already has max running vms (count includes system VMs). Cannot" +
+                    " migrate to this host");
+        }
+
+        VMInstanceVO migratedVm = _itMgr.migrateWithStorage(vm, srcHostId, destinationHost.getId(), volToPoolObjectMap);
+        return migratedVm;
+    }
+
     @DB
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VM_MOVE, eventDescription = "move VM to another user", async = false)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/vm/VirtualMachineManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java
index 4a30d97..ea9f7bb 100644
--- a/server/src/com/cloud/vm/VirtualMachineManager.java
+++ b/server/src/com/cloud/vm/VirtualMachineManager.java
@@ -20,6 +20,7 @@ import java.net.URI;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
@@ -41,6 +42,7 @@ import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
 import com.cloud.user.Account;
 import com.cloud.user.User;
 import com.cloud.utils.Pair;
@@ -109,6 +111,8 @@ public interface VirtualMachineManager extends Manager {
 
     <T extends VMInstanceVO> T migrate(T vm, long srcHostId, DeployDestination dest) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
 
+    <T extends VMInstanceVO> T migrateWithStorage(T vm, long srcId, long destId, Map<VolumeVO, StoragePoolVO> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException;
+
     <T extends VMInstanceVO> T reboot(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account) throws InsufficientCapacityException, ResourceUnavailableException;
 
     <T extends VMInstanceVO> T advanceReboot(T vm, Map<VirtualMachineProfile.Param, Object> params, User caller, Account account) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, OperationTimedoutException;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
index 19f4005..2ecece2 100755
--- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java
@@ -38,7 +38,12 @@ import javax.naming.ConfigurationException;
 
 import com.cloud.capacity.CapacityManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 
 import com.cloud.dc.*;
 import com.cloud.agent.api.*;
@@ -50,6 +55,8 @@ import com.cloud.agent.Listener;
 import com.cloud.agent.api.StartupRoutingCommand.VmState;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.agent.manager.Commands;
 import com.cloud.agent.manager.allocator.HostAllocator;
 import com.cloud.alert.AlertManager;
@@ -57,6 +64,7 @@ import com.cloud.cluster.ClusterManager;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
@@ -111,10 +119,13 @@ import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.VolumeManager;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.GuestOSCategoryDao;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.User;
@@ -164,6 +175,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Inject
     protected ServiceOfferingDao _offeringDao;
     @Inject
+    protected DiskOfferingDao _diskOfferingDao;
+    @Inject
     protected VMTemplateDao _templateDao;
     @Inject
     protected UserDao _userDao;
@@ -202,13 +215,19 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
     @Inject
     protected DataCenterDao _dcDao;
     @Inject
+    protected ClusterDao _clusterDao;
+    @Inject
     protected PrimaryDataStoreDao _storagePoolDao;
     @Inject
     protected HypervisorGuruManager _hvGuruMgr;
     @Inject
     protected NetworkDao _networkDao;
     @Inject
+    protected StoragePoolHostDao _poolHostDao;
+    @Inject
     protected VMSnapshotDao _vmSnapshotDao;
+    @Inject
+    protected VolumeDataFactory volFactory;
 
     protected List<DeploymentPlanner> _planners;
     public List<DeploymentPlanner> getPlanners() {
@@ -226,10 +245,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
 		this._hostAllocators = _hostAllocators;
 	}
 
-	@Inject
+    @Inject
+    protected List<StoragePoolAllocator> _storagePoolAllocators;
+
+    @Inject
     protected ResourceManager _resourceMgr;
 
     @Inject
+    protected SnapshotManager _snapshotMgr;
+
+    @Inject
     protected VMSnapshotManager _vmSnapshotMgr = null;
     @Inject
     protected ClusterDetailsDao  _clusterDetailsDao;
@@ -1427,6 +1452,189 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
         }
     }
 
+    private Map<VolumeVO, StoragePoolVO> getPoolListForVolumesForMigration(VirtualMachineProfile<VMInstanceVO> profile,
+            Host host, Map<VolumeVO, StoragePoolVO> volumeToPool) {
+        List<VolumeVO> allVolumes = _volsDao.findUsableVolumesForInstance(profile.getId());
+        for (VolumeVO volume : allVolumes) {
+            StoragePoolVO pool = volumeToPool.get(volume);
+            DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+            StoragePoolVO currentPool = _storagePoolDao.findById(volume.getPoolId());
+            if (pool != null) {
+                // Check if pool is accessible from the destination host and disk offering with which the volume was
+                // created is compliant with the pool type.
+                if (_poolHostDao.findByPoolHost(pool.getId(), host.getId()) == null ||
+                        pool.isLocal() != diskOffering.getUseLocalStorage()) {
+                    // Cannot find a pool for the volume. Throw an exception.
+                    throw new CloudRuntimeException("Cannot migrate volume " + volume + " to storage pool " + pool +
+                            " while migrating vm to host " + host + ". Either the pool is not accessible from the " +
+                            "host or because of the offering with which the volume is created it cannot be placed on " +
+                            "the given pool.");
+                } else if (pool.getId() == currentPool.getId()){
+                    // If the pool to migrate too is the same as current pool, remove the volume from the list of
+                    // volumes to be migrated.
+                    volumeToPool.remove(volume);
+                }
+            } else {
+                // Find a suitable pool for the volume. Call the storage pool allocator to find the list of pools.
+                DiskProfile diskProfile = new DiskProfile(volume, diskOffering, profile.getHypervisorType());
+                DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(),
+                        host.getClusterId(), host.getId(), null, null);
+                ExcludeList avoid = new ExcludeList();
+                boolean currentPoolAvailable = false;
+
+                for (StoragePoolAllocator allocator : _storagePoolAllocators) {
+                    List<StoragePool> poolList = allocator.allocateToPool(diskProfile, profile, plan, avoid,
+                            StoragePoolAllocator.RETURN_UPTO_ALL);
+                    if (poolList != null && !poolList.isEmpty()) {
+                        // Volume needs to be migrated. Pick the first pool from the list. Add a mapping to migrate the
+                        // volume to a pool only if it is required; that is the current pool on which the volume resides
+                        // is not available on the destination host.
+                        if (poolList.contains(currentPool)) {
+                            currentPoolAvailable = true;
+                        } else {
+                            volumeToPool.put(volume, _storagePoolDao.findByUuid(poolList.get(0).getUuid()));
+                        }
+
+                        break;
+                    }
+                }
+
+                if (!currentPoolAvailable && !volumeToPool.containsKey(volume)) {
+                    // Cannot find a pool for the volume. Throw an exception.
+                    throw new CloudRuntimeException("Cannot find a storage pool which is available for volume " +
+                            volume + " while migrating virtual machine " + profile.getVirtualMachine() + " to host " +
+                            host);
+                }
+            }
+        }
+
+        return volumeToPool;
+    }
+
+    private <T extends VMInstanceVO> void moveVmToMigratingState(T vm, Long hostId, ItWorkVO work)
+            throws ConcurrentOperationException {
+        // Put the vm in migrating state.
+        try {
+            if (!changeState(vm, Event.MigrationRequested, hostId, work, Step.Migrating)) {
+                s_logger.info("Migration cancelled because state has changed: " + vm);
+                throw new ConcurrentOperationException("Migration cancelled because state has changed: " + vm);
+            }
+        } catch (NoTransitionException e) {
+            s_logger.info("Migration cancelled because " + e.getMessage());
+            throw new ConcurrentOperationException("Migration cancelled because " + e.getMessage());
+        }
+    }
+
+    private <T extends VMInstanceVO> void moveVmOutofMigratingStateOnSuccess(T vm, Long hostId, ItWorkVO work)
+            throws ConcurrentOperationException {
+        // Put the vm in running state.
+        try {
+            if (!changeState(vm, Event.OperationSucceeded, hostId, work, Step.Started)) {
+                s_logger.error("Unable to change the state for " + vm);
+                throw new ConcurrentOperationException("Unable to change the state for " + vm);
+            }
+        } catch (NoTransitionException e) {
+            s_logger.error("Unable to change state due to " + e.getMessage());
+            throw new ConcurrentOperationException("Unable to change state due to " + e.getMessage());
+        }
+    }
+
+    @Override
+    public <T extends VMInstanceVO> T migrateWithStorage(T vm, long srcHostId, long destHostId,
+            Map<VolumeVO, StoragePoolVO> volumeToPool) throws ResourceUnavailableException, ConcurrentOperationException,
+            ManagementServerException, VirtualMachineMigrationException {
+
+        HostVO srcHost = _hostDao.findById(srcHostId);
+        HostVO destHost = _hostDao.findById(destHostId);
+        VirtualMachineGuru<T> vmGuru = getVmGuru(vm);
+
+        DataCenterVO dc = _dcDao.findById(destHost.getDataCenterId());
+        HostPodVO pod = _podDao.findById(destHost.getPodId());
+        Cluster cluster = _clusterDao.findById(destHost.getClusterId());
+        DeployDestination destination = new DeployDestination(dc, pod, cluster, destHost);
+
+        // Create a map of which volume should go in which storage pool.
+        long vmId = vm.getId();
+        vm = vmGuru.findById(vmId);
+        VirtualMachineProfile<VMInstanceVO> profile = new VirtualMachineProfileImpl<VMInstanceVO>(vm);
+        volumeToPool = getPoolListForVolumesForMigration(profile, destHost, volumeToPool);
+
+        // If none of the volumes have to be migrated, fail the call. Administrator needs to make a call for migrating
+        // a vm and not migrating a vm with storage.
+        if (volumeToPool.isEmpty()) {
+            throw new InvalidParameterValueException("Migration of the vm " + vm + "from host " + srcHost +
+                    " to destination host " + destHost + " doesn't involve migrating the volumes.");
+        }
+
+        short alertType = AlertManager.ALERT_TYPE_USERVM_MIGRATE;
+        if (VirtualMachine.Type.DomainRouter.equals(vm.getType())) {
+            alertType = AlertManager.ALERT_TYPE_DOMAIN_ROUTER_MIGRATE;
+        } else if (VirtualMachine.Type.ConsoleProxy.equals(vm.getType())) {
+            alertType = AlertManager.ALERT_TYPE_CONSOLE_PROXY_MIGRATE;
+        }
+
+        _networkMgr.prepareNicForMigration(profile, destination);
+        this.volumeMgr.prepareForMigration(profile, destination);
+        HypervisorGuru hvGuru = _hvGuruMgr.getGuru(vm.getHypervisorType());
+        VirtualMachineTO to = hvGuru.implement(profile);
+
+        ItWorkVO work = new ItWorkVO(UUID.randomUUID().toString(), _nodeId, State.Migrating, vm.getType(), vm.getId());
+        work.setStep(Step.Prepare);
+        work.setResourceType(ItWorkVO.ResourceType.Host);
+        work.setResourceId(destHostId);
+        work = _workDao.persist(work);
+
+        // Put the vm in migrating state.
+        vm.setLastHostId(srcHostId);
+        moveVmToMigratingState(vm, destHostId, work);
+
+        boolean migrated = false;
+        try {
+            // Migrate the vm and its volume.
+            this.volumeMgr.migrateVolumes(vm, to, srcHost, destHost, volumeToPool);
+
+            // Put the vm back to running state.
+            moveVmOutofMigratingStateOnSuccess(vm, destHost.getId(), work);
+
+            try {
+                if (!checkVmOnHost(vm, destHostId)) {
+                    s_logger.error("Vm not found on destination host. Unable to complete migration for " + vm);
+                    try {
+                        _agentMgr.send(srcHostId, new Commands(cleanup(vm.getInstanceName())), null);
+                    } catch (AgentUnavailableException e) {
+                        s_logger.error("AgentUnavailableException while cleanup on source host: " + srcHostId);
+                    }
+                    cleanup(vmGuru, new VirtualMachineProfileImpl<T>(vm), work, Event.AgentReportStopped, true,
+                            _accountMgr.getSystemUser(), _accountMgr.getSystemAccount());
+                    return null;
+                }
+            } catch (OperationTimedoutException e) {
+                s_logger.warn("Error while checking the vm " + vm + " is on host " + destHost, e);
+            }
+
+            migrated = true;
+            return vm;
+        } finally {
+            if (!migrated) {
+                s_logger.info("Migration was unsuccessful.  Cleaning up: " + vm);
+                _alertMgr.sendAlert(alertType, srcHost.getDataCenterId(), srcHost.getPodId(), "Unable to migrate vm " +
+                        vm.getInstanceName() + " from host " + srcHost.getName() + " in zone " + dc.getName() +
+                        " and pod " + dc.getName(), "Migrate Command failed.  Please check logs.");
+                try {
+                    _agentMgr.send(destHostId, new Commands(cleanup(vm.getInstanceName())), null);
+                    stateTransitTo(vm, Event.OperationFailed, srcHostId);
+                } catch (AgentUnavailableException e) {
+                    s_logger.warn("Looks like the destination Host is unavailable for cleanup.", e);
+                } catch (NoTransitionException e) {
+                    s_logger.error("Error while transitioning vm from migrating to running state.", e);
+                }
+            }
+
+            work.setStep(Step.Done);
+            _workDao.update(work.getId(), work);
+        }
+    }
+
     @Override
     public VirtualMachineTO toVmTO(VirtualMachineProfile<? extends VMInstanceVO> profile) {
         HypervisorGuru hvGuru = _hvGuruMgr.getGuru(profile.getVirtualMachine().getHypervisorType());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/test/com/cloud/vm/MockUserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java
index fd826d9..0d0a8f4 100644
--- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java
+++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java
@@ -367,6 +367,14 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager,
     }
 
     @Override
+    public VirtualMachine migrateVirtualMachineWithVolume(Long vmId, Host destinationHost, Map<String, String> volumeToPool)
+            throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException,
+            VirtualMachineMigrationException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
     public UserVm moveVMToUser(AssignVMCmd moveUserVMCmd)
             throws ResourceAllocationException, ConcurrentOperationException,
             ResourceUnavailableException, InsufficientCapacityException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
index 4917e77..94ddea6 100755
--- a/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
+++ b/server/test/com/cloud/vm/MockVirtualMachineManagerImpl.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.springframework.stereotype.Component;
 
 import com.cloud.agent.api.to.NicTO;
@@ -45,6 +46,7 @@ import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VolumeVO;
 import com.cloud.user.Account;
 import com.cloud.user.User;
 import com.cloud.utils.Pair;
@@ -143,6 +145,14 @@ public class MockVirtualMachineManagerImpl extends ManagerBase implements Virtua
     }
 
     @Override
+    public <T extends VMInstanceVO> T migrateWithStorage(T vm, long srcHostId, long destHostId,
+            Map<VolumeVO, StoragePoolVO> volumeToPool) throws ResourceUnavailableException,
+            ConcurrentOperationException, ManagementServerException, VirtualMachineMigrationException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
     public VMInstanceVO findByIdAndType(Type type, long vmId) {
         // TODO Auto-generated method stub
         return null;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/21ce3bef/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java b/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java
index 322f051..dd51e74 100644
--- a/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java
+++ b/server/test/com/cloud/vm/VirtualMachineManagerImplTest.java
@@ -31,6 +31,41 @@ import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.VolumeManager;
 import com.cloud.storage.VolumeVO;
+import com.cloud.agent.api.PrepareForMigrationAnswer;
+import com.cloud.agent.api.PrepareForMigrationCommand;
+import com.cloud.agent.api.MigrateWithStorageAnswer;
+import com.cloud.agent.api.MigrateWithStorageCommand;
+import com.cloud.agent.api.MigrateWithStorageReceiveAnswer;
+import com.cloud.agent.api.MigrateWithStorageReceiveCommand;
+import com.cloud.agent.api.MigrateWithStorageSendAnswer;
+import com.cloud.agent.api.MigrateWithStorageSendCommand;
+import com.cloud.agent.api.MigrateWithStorageCompleteAnswer;
+import com.cloud.agent.api.MigrateWithStorageCompleteCommand;
+import com.cloud.agent.api.CheckVirtualMachineAnswer;
+import com.cloud.agent.api.CheckVirtualMachineCommand;
+import com.cloud.capacity.CapacityManager;
+import com.cloud.configuration.ConfigurationManager;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.ManagementServerException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.exception.VirtualMachineMigrationException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.HypervisorGuru;
+import com.cloud.hypervisor.HypervisorGuruManager;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.NetworkManager;
+import com.cloud.storage.DiskOfferingVO;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.VolumeManager;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.user.*;
@@ -41,20 +76,33 @@ import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
 import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
+import com.cloud.utils.Pair;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.dao.VMInstanceDao;
+import com.cloud.vm.snapshot.VMSnapshotManager;
+import com.cloud.vm.VirtualMachine.Event;
+import com.cloud.vm.VirtualMachine.State;
+
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+
 import org.junit.Test;
 import org.junit.Before;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Mockito.*;
 
-
 import java.lang.reflect.Field;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
 
 public class VirtualMachineManagerImplTest {
 
-
         @Spy VirtualMachineManagerImpl _vmMgr = new VirtualMachineManagerImpl();
         @Mock
         VolumeManager _storageMgr;
@@ -106,6 +154,25 @@ public class VirtualMachineManagerImplTest {
         List<VolumeVO> _rootVols;
         @Mock
         ItWorkVO _work;
+
+        @Mock ClusterDao _clusterDao;
+        @Mock HostPodDao _podDao;
+        @Mock DataCenterDao _dcDao;
+        @Mock DiskOfferingDao _diskOfferingDao;
+        @Mock PrimaryDataStoreDao _storagePoolDao;
+        @Mock StoragePoolHostDao _poolHostDao;
+        @Mock NetworkManager _networkMgr;
+        @Mock HypervisorGuruManager _hvGuruMgr;
+        @Mock VMSnapshotManager _vmSnapshotMgr;
+
+        // Mock objects for vm migration with storage test.
+        @Mock DiskOfferingVO _diskOfferingMock;
+        @Mock StoragePoolVO _srcStoragePoolMock;
+        @Mock StoragePoolVO _destStoragePoolMock;
+        @Mock HostVO _srcHostMock;
+        @Mock HostVO _destHostMock;
+        @Mock Map<VolumeVO, StoragePoolVO> _volumeToPoolMock;
+
         @Before
         public void setup(){
             MockitoAnnotations.initMocks(this);
@@ -122,6 +189,16 @@ public class VirtualMachineManagerImplTest {
             _vmMgr._nodeId = 1L;
             _vmMgr._workDao = _workDao;
             _vmMgr._agentMgr = _agentMgr;
+            _vmMgr._podDao = _podDao;
+            _vmMgr._clusterDao = _clusterDao;
+            _vmMgr._dcDao = _dcDao;
+            _vmMgr._diskOfferingDao = _diskOfferingDao;
+            _vmMgr._storagePoolDao = _storagePoolDao;
+            _vmMgr._poolHostDao= _poolHostDao;
+            _vmMgr._networkMgr = _networkMgr;
+            _vmMgr._hvGuruMgr = _hvGuruMgr;
+            _vmMgr._vmSnapshotMgr = _vmSnapshotMgr;
+            _vmMgr._vmDao = _vmInstanceDao;
 
             when(_vmMock.getId()).thenReturn(314l);
             when(_vmInstance.getId()).thenReturn(1L);
@@ -204,5 +281,155 @@ public class VirtualMachineManagerImplTest {
         return serviceOffering;
     }
 
+    private void initializeMockConfigForMigratingVmWithVolumes() throws OperationTimedoutException,
+        ResourceUnavailableException {
+
+        // Mock the source and destination hosts.
+        when(_srcHostMock.getId()).thenReturn(5L);
+        when(_destHostMock.getId()).thenReturn(6L);
+        when(_hostDao.findById(5L)).thenReturn(_srcHostMock);
+        when(_hostDao.findById(6L)).thenReturn(_destHostMock);
+
+        // Mock the vm being migrated.
+        when(_vmMock.getId()).thenReturn(1L);
+        when(_vmMock.getHypervisorType()).thenReturn(HypervisorType.XenServer);
+        when(_vmMock.getState()).thenReturn(State.Running).thenReturn(State.Running).thenReturn(State.Migrating)
+            .thenReturn(State.Migrating);
+        when(_vmMock.getHostId()).thenReturn(5L);
+        when(_vmInstance.getId()).thenReturn(1L);
+        when(_vmInstance.getServiceOfferingId()).thenReturn(2L);
+        when(_vmInstance.getInstanceName()).thenReturn("myVm");
+        when(_vmInstance.getHostId()).thenReturn(5L);
+        when(_vmInstance.getType()).thenReturn(VirtualMachine.Type.User);
+        when(_vmInstance.getState()).thenReturn(State.Running).thenReturn(State.Running).thenReturn(State.Migrating)
+            .thenReturn(State.Migrating);
+
+        // Mock the work item.
+        when(_workDao.persist(any(ItWorkVO.class))).thenReturn(_work);
+        when(_workDao.update("1", _work)).thenReturn(true);
+        when(_work.getId()).thenReturn("1");
+        doNothing().when(_work).setStep(ItWorkVO.Step.Done);
+
+        // Mock the vm guru and the user vm object that gets returned.
+        _vmMgr._vmGurus = new HashMap<VirtualMachine.Type, VirtualMachineGuru<? extends VMInstanceVO>>();
+        UserVmManagerImpl userVmManager = mock(UserVmManagerImpl.class);
+        _vmMgr.registerGuru(VirtualMachine.Type.User, userVmManager);
+        when(userVmManager.findById(anyLong())).thenReturn(_vmMock);
+
+        // Mock the iteration over all the volumes of an instance.
+        Iterator<VolumeVO> volumeIterator = mock(Iterator.class);
+        when(_volsDao.findUsableVolumesForInstance(anyLong())).thenReturn(_rootVols);
+        when(_rootVols.iterator()).thenReturn(volumeIterator);
+        when(volumeIterator.hasNext()).thenReturn(true, false);
+        when(volumeIterator.next()).thenReturn(_volumeMock);
+
+        // Mock the disk offering and pool objects for a volume.
+        when(_volumeMock.getDiskOfferingId()).thenReturn(5L);
+        when(_volumeMock.getPoolId()).thenReturn(200L);
+        when(_diskOfferingDao.findById(anyLong())).thenReturn(_diskOfferingMock);
+        when(_storagePoolDao.findById(anyLong())).thenReturn(_srcStoragePoolMock);
+
+        // Mock the volume to pool mapping.
+        when(_volumeToPoolMock.get(_volumeMock)).thenReturn(_destStoragePoolMock);
+        when(_destStoragePoolMock.getId()).thenReturn(201L);
+        when(_srcStoragePoolMock.getId()).thenReturn(200L);
+        when(_destStoragePoolMock.isLocal()).thenReturn(false);
+        when(_diskOfferingMock.getUseLocalStorage()).thenReturn(false);
+        when(_poolHostDao.findByPoolHost(anyLong(), anyLong())).thenReturn(mock(StoragePoolHostVO.class));
+
+        // Mock hypervisor guru.
+        HypervisorGuru guruMock = mock(HypervisorGuru.class);
+        when(_hvGuruMgr.getGuru(HypervisorType.XenServer)).thenReturn(guruMock);
+
+        when(_srcHostMock.getClusterId()).thenReturn(3L);
+        when(_destHostMock.getClusterId()).thenReturn(3L);
+
+        // Mock the commands and answers to the agent.
+        PrepareForMigrationAnswer prepAnswerMock = mock(PrepareForMigrationAnswer.class);
+        when(prepAnswerMock.getResult()).thenReturn(true);
+        when(_agentMgr.send(anyLong(), isA(PrepareForMigrationCommand.class))).thenReturn(prepAnswerMock);
+
+        MigrateWithStorageAnswer migAnswerMock = mock(MigrateWithStorageAnswer.class);
+        when(migAnswerMock.getResult()).thenReturn(true);
+        when(_agentMgr.send(anyLong(), isA(MigrateWithStorageCommand.class))).thenReturn(migAnswerMock);
+
+        MigrateWithStorageReceiveAnswer migRecAnswerMock = mock(MigrateWithStorageReceiveAnswer.class);
+        when(migRecAnswerMock.getResult()).thenReturn(true);
+        when(_agentMgr.send(anyLong(), isA(MigrateWithStorageReceiveCommand.class))).thenReturn(migRecAnswerMock);
+
+        MigrateWithStorageSendAnswer migSendAnswerMock = mock(MigrateWithStorageSendAnswer.class);
+        when(migSendAnswerMock.getResult()).thenReturn(true);
+        when(_agentMgr.send(anyLong(), isA(MigrateWithStorageSendCommand.class))).thenReturn(migSendAnswerMock);
+
+        MigrateWithStorageCompleteAnswer migCompleteAnswerMock = mock(MigrateWithStorageCompleteAnswer.class);
+        when(migCompleteAnswerMock.getResult()).thenReturn(true);
+        when(_agentMgr.send(anyLong(), isA(MigrateWithStorageCompleteCommand.class))).thenReturn(migCompleteAnswerMock);
+
+        CheckVirtualMachineAnswer checkVmAnswerMock = mock(CheckVirtualMachineAnswer.class);
+        when(checkVmAnswerMock.getResult()).thenReturn(true);
+        when(checkVmAnswerMock.getState()).thenReturn(State.Running);
+        when(_agentMgr.send(anyLong(), isA(CheckVirtualMachineCommand.class))).thenReturn(checkVmAnswerMock);
+
+        // Mock the state transitions of vm.
+        Pair<Long, Long> opaqueMock = new Pair<Long, Long> (_vmMock.getHostId(), _destHostMock.getId());
+        when(_vmSnapshotMgr.hasActiveVMSnapshotTasks(anyLong())).thenReturn(false);
+        when(_vmInstanceDao.updateState(State.Running, Event.MigrationRequested, State.Migrating, _vmMock, opaqueMock))
+            .thenReturn(true);
+        when(_vmInstanceDao.updateState(State.Migrating, Event.OperationSucceeded, State.Running, _vmMock, opaqueMock))
+            .thenReturn(true);
+    }
+
+    // Check migration of a vm with its volumes within a cluster.
+    @Test
+    public void testMigrateWithVolumeWithinCluster() throws ResourceUnavailableException, ConcurrentOperationException,
+        ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException {
 
+        initializeMockConfigForMigratingVmWithVolumes();
+        when(_srcHostMock.getClusterId()).thenReturn(3L);
+        when(_destHostMock.getClusterId()).thenReturn(3L);
+
+        _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock);
+    }
+
+    // Check migration of a vm with its volumes across a cluster.
+    @Test
+    public void testMigrateWithVolumeAcrossCluster() throws ResourceUnavailableException, ConcurrentOperationException,
+        ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException {
+
+        initializeMockConfigForMigratingVmWithVolumes();
+        when(_srcHostMock.getClusterId()).thenReturn(3L);
+        when(_destHostMock.getClusterId()).thenReturn(4L);
+
+        _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock);
+    }
+
+    // Check migration of a vm fails when src and destination pool are not of same type; that is, one is shared and
+    // other is local.
+    @Test(expected=CloudRuntimeException.class)
+    public void testMigrateWithVolumeFail1() throws ResourceUnavailableException, ConcurrentOperationException,
+        ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException {
+
+        initializeMockConfigForMigratingVmWithVolumes();
+        when(_srcHostMock.getClusterId()).thenReturn(3L);
+        when(_destHostMock.getClusterId()).thenReturn(3L);
+
+        when(_destStoragePoolMock.isLocal()).thenReturn(true);
+        when(_diskOfferingMock.getUseLocalStorage()).thenReturn(false);
+
+        _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock);
+    }
+
+    // Check migration of a vm fails when vm is not in Running state.
+    @Test(expected=ConcurrentOperationException.class)
+    public void testMigrateWithVolumeFail2() throws ResourceUnavailableException, ConcurrentOperationException,
+        ManagementServerException, VirtualMachineMigrationException, OperationTimedoutException {
+
+        initializeMockConfigForMigratingVmWithVolumes();
+        when(_srcHostMock.getClusterId()).thenReturn(3L);
+        when(_destHostMock.getClusterId()).thenReturn(3L);
+
+        when(_vmMock.getState()).thenReturn(State.Stopped);
+
+        _vmMgr.migrateWithStorage(_vmInstance, _srcHostMock.getId(), _destHostMock.getId(), _volumeToPoolMock);
+    }
 }


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

Posted by ts...@apache.org.
fix CLOUDSTACK-2061 Hitting java NPE in addNicToVirtualMachine api when trying to add a shared network to a VM


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

Branch: refs/heads/marvin_refactor
Commit: dfbe11355c40a5dbe022f022426c100c53428901
Parents: 985b2aa
Author: Mice Xia <mi...@tcloudcomputing.com>
Authored: Thu Apr 18 14:56:44 2013 +0800
Committer: Mice Xia <mi...@tcloudcomputing.com>
Committed: Thu Apr 18 14:57:37 2013 +0800

----------------------------------------------------------------------
 .../network/element/VirtualRouterElement.java      |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/dfbe1135/server/src/com/cloud/network/element/VirtualRouterElement.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java
index 169db32..f601f4f 100755
--- a/server/src/com/cloud/network/element/VirtualRouterElement.java
+++ b/server/src/com/cloud/network/element/VirtualRouterElement.java
@@ -876,8 +876,8 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl
         if (publicNetwork) {
             routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER);
         } else {
-            Long podId = dest.getPod().getId();
             if (isPodBased) {
+                Long podId = dest.getPod().getId();
                 routers = _routerDao.listByNetworkAndPodAndRole(network.getId(), podId, Role.VIRTUAL_ROUTER);
             } else {
                 routers = _routerDao.listByNetworkAndRole(network.getId(), Role.VIRTUAL_ROUTER);


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

Posted by ts...@apache.org.
Add UI 'module' API

Add a variant to a plugin, called a 'module.' It is designed for
features that are build-in to the standard UI (i.e., not installed
dynamically), but can still utilize the modular nature of UI
plugins. It works exactly the same way as a plugin, except:

-Modules are added to modules/ folder
-Modules are registered in modules/modules.js
-No config.js (no need for metadata, since they are built-in features)
- /ui/modules/ folder will not be touched by the build system, so any modules
 are committed directly to the ui/ folder. In other words, modules are
 not installed automatically.


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

Branch: refs/heads/marvin_refactor
Commit: 6babaf96163f18453eeb7de69857ec62f01d88b3
Parents: 9573f51
Author: Brian Federle <br...@citrix.com>
Authored: Thu Apr 18 12:34:59 2013 -0700
Committer: Brian Federle <br...@citrix.com>
Committed: Thu Apr 18 12:52:55 2013 -0700

----------------------------------------------------------------------
 ui/index.jsp          |    3 +-
 ui/modules/modules.js |   20 +++++++++++
 ui/scripts/plugins.js |   78 +++++++++++++++++++++++++++++++-------------
 3 files changed, 77 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6babaf96/ui/index.jsp
----------------------------------------------------------------------
diff --git a/ui/index.jsp b/ui/index.jsp
index 550661e..5e5a7f2 100644
--- a/ui/index.jsp
+++ b/ui/index.jsp
@@ -1680,9 +1680,10 @@ under the License.
     <script type="text/javascript" src="scripts/docs.js?t=<%=now%>"></script>
     <script type="text/javascript" src="scripts/vm_snapshots.js?t=<%=now%>"></script>  
 
-    <!-- Plugins -->
+    <!-- Plugin/module API -->
     <script type="text/javascript" src="scripts/ui-custom/pluginListing.js?t=<%=now%>"></script>
     <script type="text/javascript" src="plugins/plugins.js?t=<%=now%>"></script>
+    <script type="text/javascript" src="modules/modules.js?t=<%=now%>"></script>
     <script type="text/javascript" src="scripts/plugins.js?t=<%=now%>"></script>
   </body>
 </html>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6babaf96/ui/modules/modules.js
----------------------------------------------------------------------
diff --git a/ui/modules/modules.js b/ui/modules/modules.js
new file mode 100644
index 0000000..490749f
--- /dev/null
+++ b/ui/modules/modules.js
@@ -0,0 +1,20 @@
+// 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.
+(function($, cloudStack) {
+  cloudStack.modules = [
+  ];
+}(jQuery, cloudStack));

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6babaf96/ui/scripts/plugins.js
----------------------------------------------------------------------
diff --git a/ui/scripts/plugins.js b/ui/scripts/plugins.js
index d3e0705..9d1991c 100644
--- a/ui/scripts/plugins.js
+++ b/ui/scripts/plugins.js
@@ -15,6 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 (function($, cloudStack, require) {
+  if (!cloudStack.pluginAPI) cloudStack.pluginAPI = {};
+
   var loadCSS = function(path) {
     var $link = $('<link>');
 
@@ -27,27 +29,29 @@
     $('head').append($link);
   };
 
-  var pluginAPI = {
-    pollAsyncJob: pollAsyncJobResult,
-    apiCall: function(command, args) {
-      $.ajax({
-        url: createURL(command),
-        data: args.data,
-        success: args.success,
-        error: function(json) {
-          args.error(parseXMLHttpResponse(json));
-        }
-      })
-    },
-    addSection: function(section) {
-      cloudStack.sections[section.id] = $.extend(section, {
-        customIcon: 'plugins/' + section.id + '/icon.png'
-      });
-    },
-    extend: function(obj) {
-      $.extend(true, cloudStack, obj);
+  $.extend(cloudStack.pluginAPI, {
+    ui: {
+      pollAsyncJob: pollAsyncJobResult,
+      apiCall: function(command, args) {
+        $.ajax({
+          url: createURL(command),
+          data: args.data,
+          success: args.success,
+          error: function(json) {
+            args.error(parseXMLHttpResponse(json));
+          }
+        })
+      },
+      addSection: function(section) {
+        cloudStack.sections[section.id] = $.extend(section, {
+          customIcon: 'plugins/' + section.id + '/icon.png'
+        });
+      },
+      extend: function(obj) {
+        $.extend(true, cloudStack, obj);
+      }
     }
-  };
+  });
   
   cloudStack.sections.plugins = {
     title: 'label.plugins',
@@ -66,9 +70,37 @@
       loadCSS(pluginCSS);
 
       // Execute plugin
-      cloudStack.plugins[pluginID]({
-        ui: pluginAPI
-      });
+      cloudStack.plugins[pluginID](
+        $.extend(true, {}, cloudStack.pluginAPI, {
+          pluginAPI: {
+            extend: function(api) {
+              cloudStack.pluginAPI[pluginID] = api;
+            }
+          }
+        })
+      );
+    });
+  });
+
+  // Load modules
+  $(cloudStack.modules).map(function(index, moduleID) {
+    var basePath = 'modules/' + moduleID + '/';
+    var moduleJS = basePath + moduleID + '.js';
+    var moduleCSS = basePath + moduleID + '.css';
+
+    require([moduleJS], function() {
+      loadCSS(moduleCSS);
+
+      // Execute module
+      cloudStack.modules[moduleID](
+        $.extend(true, {}, cloudStack.pluginAPI, {
+          pluginAPI: {
+            extend: function(api) {
+              cloudStack.pluginAPI[moduleID] = api;
+            }
+          }
+        })
+      );
     });
   });
 }(jQuery, cloudStack, require));


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

Posted by ts...@apache.org.
CLOUDSTACK-2083 router never comes to running state when addNicToVirtualMachine api is called with network id which is only allocated


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

Branch: refs/heads/marvin_refactor
Commit: 4fd921269bdce3ea55bb63ac5226ff52e6a82e9d
Parents: f8d4a23
Author: Mice Xia <mi...@tcloudcomputing.com>
Authored: Fri Apr 19 10:45:43 2013 +0800
Committer: Mice Xia <mi...@tcloudcomputing.com>
Committed: Fri Apr 19 10:52:00 2013 +0800

----------------------------------------------------------------------
 .../src/com/cloud/network/NetworkManagerImpl.java  |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/4fd92126/server/src/com/cloud/network/NetworkManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java
index 114402b..72ccac0 100755
--- a/server/src/com/cloud/network/NetworkManagerImpl.java
+++ b/server/src/com/cloud/network/NetworkManagerImpl.java
@@ -3636,8 +3636,8 @@ public class NetworkManagerImpl extends ManagerBase implements NetworkManager, L
                 
                 //2) prepare nic
                 if (prepare) {
-                    NetworkVO networkVO = _networksDao.findById(network.getId());
-                    nic = prepareNic(vmProfile, dest, context, nic.getId(), networkVO);
+                    Pair<NetworkGuru, NetworkVO> implemented = implementNetwork(nic.getNetworkId(), dest, context);
+                    nic = prepareNic(vmProfile, dest, context, nic.getId(), implemented.second());
                     s_logger.debug("Nic is prepared successfully for vm " + vm + " in network " + network);
                 }
                 


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

Posted by ts...@apache.org.
one shot creation of factories

Build phase will init the bare minimum object required to make the web
request to the mgmt server

Create phase will make the actual request and fill the attributes of the
entity after recieving the response

This allows for one shot creation of the entity using:
EntityFactory.create(apiclient)

over two steps:
factory = EntityFactory()
entity = Entity.create(apiclient, factory)

TODO:
Figure out howto perform related factory creation.
eg: UserFactory.create() inits AccountFactory.create()

Signed-off-by: Prasanna Santhanam <ts...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 3814eb323128770e8bedc061daa586f6fc1b2802
Parents: d915fb2
Author: Prasanna Santhanam <ts...@apache.org>
Authored: Fri Apr 19 16:49:16 2013 +0530
Committer: Prasanna Santhanam <ts...@apache.org>
Committed: Fri Apr 19 16:49:16 2013 +0530

----------------------------------------------------------------------
 .../integration/lib/factory/AccountFactory.py      |    1 +
 .../lib/factory/CloudStackBaseFactory.py           |   24 ++++-
 .../marvin/integration/lib/factory/UserFactory.py  |    4 +-
 .../integration/lib/factory/test/testFactories.py  |   81 ++++++++-------
 4 files changed, 71 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3814eb32/tools/marvin/marvin/integration/lib/factory/AccountFactory.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/factory/AccountFactory.py b/tools/marvin/marvin/integration/lib/factory/AccountFactory.py
index 7306073..00399e4 100644
--- a/tools/marvin/marvin/integration/lib/factory/AccountFactory.py
+++ b/tools/marvin/marvin/integration/lib/factory/AccountFactory.py
@@ -20,6 +20,7 @@ from marvin.integration.lib.factory.CloudStackBaseFactory import *
 from marvin.integration.lib.base import Account
 from marvin.integration.lib.utils import random_gen
 
+@factory.use_strategy(new_strategy=factory.BUILD_STRATEGY)
 class AccountFactory(CloudStackBaseFactory):
 
     FACTORY_FOR = Account.Account

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3814eb32/tools/marvin/marvin/integration/lib/factory/CloudStackBaseFactory.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/factory/CloudStackBaseFactory.py b/tools/marvin/marvin/integration/lib/factory/CloudStackBaseFactory.py
index 57d7779..ff10754 100644
--- a/tools/marvin/marvin/integration/lib/factory/CloudStackBaseFactory.py
+++ b/tools/marvin/marvin/integration/lib/factory/CloudStackBaseFactory.py
@@ -16,12 +16,34 @@
 # under the License.
 
 import factory
+import inspect
+
+CREATORS = ["create", "deploy"]
+
 
 class CloudStackBaseFactory(factory.Factory):
     ABSTRACT_FACTORY = True
 
     @classmethod
-    def _create(cls, target_class, *args, **kwargs):
+    def _build(cls, target_class, *args, **kwargs):
         if len(args) == 0:
             return target_class(kwargs)
         return target_class(*args, **kwargs)
+
+    @classmethod
+    def _create(cls, target_class, *args, **kwargs):
+        if "apiclient" in kwargs:
+            members = inspect.getmembers(target_class,
+                                         predicate=inspect.ismethod)
+            creators = filter(lambda x: x[0] in CREATORS, members)
+            assert creators, "How do I bring this guy into existence?"
+            assert inspect.ismethod(creators[0][1])
+            creator = creators[0][1]
+            apiclient = kwargs["apiclient"]
+            clean_kwargs = dict((k, v) for k, v in kwargs.iteritems()
+                                if k != "apiclient")
+            return creator(apiclient, factory=cls._build(target_class,
+                                                         *args, **clean_kwargs)
+                                                        )
+        else:
+            cls._build(target_class, *args, **kwargs)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3814eb32/tools/marvin/marvin/integration/lib/factory/UserFactory.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/factory/UserFactory.py b/tools/marvin/marvin/integration/lib/factory/UserFactory.py
index 1b13b8b..84218c1 100644
--- a/tools/marvin/marvin/integration/lib/factory/UserFactory.py
+++ b/tools/marvin/marvin/integration/lib/factory/UserFactory.py
@@ -23,7 +23,7 @@ class UserFactory(CloudStackBaseFactory):
 
     FACTORY_FOR = User.User
 
-    account = factory.SubFactory(AccountFactory).factory()
+    account = factory.RelatedFactory(AccountFactory).factory()
     email = account.email
     firstname = account.firstname
     lastname = account.lastname
@@ -31,4 +31,4 @@ class UserFactory(CloudStackBaseFactory):
     username = account.username
 
 class AdminUserFactory(UserFactory):
-    account = factory.SubFactory(AccountFactory, accounttype=1).factory()
+    account = factory.RelatedFactory(AccountFactory, accounttype=1).factory()

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3814eb32/tools/marvin/marvin/integration/lib/factory/test/testFactories.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/integration/lib/factory/test/testFactories.py b/tools/marvin/marvin/integration/lib/factory/test/testFactories.py
index cb7165f..41217d2 100644
--- a/tools/marvin/marvin/integration/lib/factory/test/testFactories.py
+++ b/tools/marvin/marvin/integration/lib/factory/test/testFactories.py
@@ -39,34 +39,46 @@ from marvin.integration.lib.base.VirtualMachine import VirtualMachine
 from marvin.integration.lib.factory.UserFactory import *
 from marvin.integration.lib.base.User import User
 
-class AccountFactoryTest(unittest.TestCase):
+
+class BuildVsCreateStrategyTest(unittest.TestCase):
     def setUp(self):
         self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
 
-    def test_userAccountFactory(self):
+    def tearDown(self):
+        pass
+
+    def test_buildAccountFactory(self):
         af = AccountFactory()
-        accnt = Account.create(apiclient=self.apiClient, AccountFactory=af)
-        self.assertTrue(accnt is not None, msg="no account created by factory")
-        self.assertEqual(accnt.name, af.username, msg="account names are not same")
+        self.assert_(af.username is not None, msg="Acount factory didn't initialize")
+
+    def test_createAccountFactory(self):
+        af = AccountFactory.create(apiclient=self.apiClient)
+        self.assert_(isinstance(af, Account))
+        self.assert_(af.account.id is not None, msg="Account creation failed")
+        self.assert_(af.account.domain is not None, msg="Account belongs to no domain")
+
+
+class AccountFactoryTest(unittest.TestCase):
+    def setUp(self):
+        self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
 
     def test_adminAccountFactory(self):
-        af = AdminAccountFactory()
-        accnt = Account.create(apiclient=self.apiClient, AccountFactory=af)
-        self.assertTrue(accnt is not None, msg="no account created by factory")
-        self.assertEqual(accnt.name, af.username, msg="account names are not same")
+        accnt = AdminAccountFactory.create(apiclient=self.apiClient)
+        self.assert_(accnt is not None, msg="no account created by factory")
+        self.assert_(accnt.account.name is not None)
 
     def test_userAccountFactoryCustomArgs(self):
-        af = AccountFactory(firstname='test', lastname='test')
-        accnt = Account.create(apiclient=self.apiClient, AccountFactory=af)
-        self.assertTrue(accnt is not None, msg="no account created by factory")
-        self.assertEqual(accnt.name, af.username, msg="account names are not same")
+        accnt = AccountFactory.create(apiclient=self.apiClient, firstname='test', lastname='test')
+        a = accnt.list(apiclient=self.apiClient, account=accnt.account.username, domainid=accnt.account.domainid)
+        self.assert_(accnt is not None, msg="no account created by factory")
+        self.assert_(accnt.account.name is not None)
 
     @unittest.skip("Job Queue gets stuck on this")
     def test_disableAccountPostFactoryGeneration(self):
         af = DomainAdminFactory()
-        domadmin = Account.create(apiclient=self.apiClient, AccountFactory=af)
-        self.assertTrue(domadmin is not None, msg="no account was created")
-        self.assertEqual(domadmin.name, af.username, msg = "account names don't match")
+        domadmin = DomainAdminFactory.create(apiclient=self.apiClient, factory=af)
+        self.assert_(domadmin is not None, msg="no account was created")
+        self.assert_(domadmin.account.name, af.username, msg = "account names don't match")
         domadmin.disable(self.apiClient, lock=True)
 
     def tearDown(self):
@@ -78,10 +90,9 @@ class ServiceOfferingFactoryTest(unittest.TestCase):
         self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
 
     def test_serviceOfferingFactory(self):
-        sf = ServiceOfferingFactory()
-        soffering = ServiceOffering.create(apiclient=self.apiClient, ServiceOfferingFactory=sf)
-        self.assertTrue(soffering is not None, msg="no service offering was created")
-        self.assertEqual(soffering.name, sf.name, msg="error in service offering factory creation")
+        soffering = ServiceOfferingFactory.create(apiclient=self.apiClient)
+        self.assert_(soffering is not None, msg="no service offering was created")
+        self.assert_(soffering.name is not None, msg="error in service offering factory creation")
 
 
     def tearDown(self):
@@ -93,19 +104,18 @@ class NetworkOfferingFactoryTest(unittest.TestCase):
         self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
 
     def test_defaultSourceNatOfferingFactory(self):
-        snatOfferingFactory = DefaultIsolatedNetworkOfferingWithSourceNatServiceFactory()
-        snatOffering = NetworkOffering.create(apiclient=self.apiClient, NetworkOfferingFactory=snatOfferingFactory)
-        self.assertTrue(snatOffering is not None, msg = "no network offering was created")
-        self.assertEqual(snatOffering.name, snatOfferingFactory.name, msg="error in network offering factory creation")
+        snatOffering = DefaultIsolatedNetworkOfferingWithSourceNatServiceFactory.create(apiclient=self.apiClient)
+        self.assert_(snatOffering is not None, msg = "no network offering was created")
+        self.assert_(snatOffering.name is not None, msg="error in network offering creation")
 
     def test_defaultSGOfferingEnable(self):
-        sgOfferingFactory = DefaultSharedNetworkOfferingWithSGServiceFactory()
-        sgOffering = NetworkOffering.create(apiclient=self.apiClient, NetworkOfferingFactory=sgOfferingFactory)
+        sgOffering = DefaultSharedNetworkOfferingWithSGServiceFactory.create(apiclient=self.apiClient)
         sgOffering.update(self.apiClient, state='Enabled')
 
     def tearDown(self):
         pass
 
+
 class VirtualMachineFactoryTest(unittest.TestCase):
     def setUp(self):
         self.apiClient = cloudstackTestClient(mgtSvr='localhost', logging=logging.getLogger('factories.cloudstack')).getApiClient()
@@ -114,13 +124,14 @@ class VirtualMachineFactoryTest(unittest.TestCase):
         pass
 
     def test_virtualMachineDeploy(self):
-        sf = ServiceOfferingFactory()
+        sf = SmallServiceOfferingFactory()
         tf = DefaultBuiltInTemplateFactory()
+        service = ServiceOffering.create(apiclient=self.apiClient, factory=sf)
         zones = Zone.list(apiclient=self.apiClient)
         template = get_template(apiclient=self.apiClient, zoneid = zones[0].id, ostype=tf.ostype)
-        vmf = VirtualMachineFactory(serviceofferingid = sf.id, templateid = template.id, zoneid = zones[0].id)
+        vmf = VirtualMachineFactory(serviceofferingid = service.id, templateid = template.id, zoneid = zones[0].id)
+        vm = VirtualMachine.deploy(apiclient=self.apiClient, factory=vmf)
 
-        vm = VirtualMachine.create(apiclient=self.apiClient, VirtualMachineFactory=vmf)
 
 class UserFactorySubFactoryTest(unittest.TestCase):
     def setUp(self):
@@ -130,10 +141,8 @@ class UserFactorySubFactoryTest(unittest.TestCase):
         pass
 
     def test_userSubFactory(self):
-        uf = UserFactory()
-        account = AccountFactory.create(apiclient=self.apiClient, AccountFactory=uf.account)
-        self.assertTrue(account is not None, msg="no account was created")
-        users = User.list(apiclient=self.apiClient, account=account.name)
-        self.assertTrue(users is not None, msg="no users were found in the account")
-        self.assertTrue(len(users) > 0, msg="user list is empty")
-        self.assertEqual(users[0].username, uf.username, msg="usernames are not same")
+        uf = UserFactory.create(apiclient=self.apiClient)
+        user = User.list(apiclient=self.apiClient, username=uf.username)
+        self.assert_(uf.username == user[0].username, msg="Usernames don't match")
+
+


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

Posted by ts...@apache.org.
Adding 2.2 to 4.1 upgrade instructions for RPM and DEB to release notes

Signed-off-by: Chip Childers <ch...@apache.org>


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

Branch: refs/heads/marvin_refactor
Commit: 7a4f70ff16706c17d1b408f48d72a7e0387cde08
Parents: 31531fa
Author: Chip Childers <ch...@apache.org>
Authored: Thu Apr 18 12:54:59 2013 -0400
Committer: Chip Childers <ch...@apache.org>
Committed: Thu Apr 18 12:54:59 2013 -0400

----------------------------------------------------------------------
 docs/en-US/Release_Notes.xml |  109 ++++++++++++++++++++++++++++++++++---
 1 files changed, 100 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/7a4f70ff/docs/en-US/Release_Notes.xml
----------------------------------------------------------------------
diff --git a/docs/en-US/Release_Notes.xml b/docs/en-US/Release_Notes.xml
index d5311e4..60209f6 100644
--- a/docs/en-US/Release_Notes.xml
+++ b/docs/en-US/Release_Notes.xml
@@ -4912,16 +4912,107 @@ service cloudstack-agent start
                         the community provided yum/apt repositories to gain access to the &PRODUCT; binaries.
                     </para>
                 </listitem>
-                <listitem>
-                    <para> After you have configured an appropriate yum or apt repository, you may execute the
-                        one of the following commands as appropriate for your environment in order to upgrade
-                        &PRODUCT;: <programlisting><prompt>#</prompt> <command>yum</command> update cloud-*</programlisting>
-                        <programlisting><prompt>#</prompt> <command>apt-get</command> update
-                            <prompt>#</prompt> <command>apt-get</command> upgrade cloud-*</programlisting>
-                    </para>
-                    <para>You will, of course, have to agree to the changes suggested by Yum or APT.</para>
+                <listitem id="upgrade-deb-packages-22">
+                    <para>If you are using Ubuntu, follow this procedure to upgrade your packages. If not, skip to step <xref linkend="upgrade-rpm-packages-22" />.</para> 
+                    <note><title>Community Packages</title>
+                        <para>This section assumes you're using the community supplied packages for &PRODUCT;. If you've created your own packages and APT repository, substitute your own URL for the ones used in these examples.</para>
+                    </note>
+                    <orderedlist id="debsteps-22">
+                        <listitem>
+                            <para>The first order of business will be to change the sources list for each system with &PRODUCT; packages. This means all management servers, and any hosts that have the KVM agent. (No changes should be necessary for hosts that are running VMware or Xen.)</para>
+                            <para>Start by opening <filename>/etc/apt/sources.list.d/cloudstack.list</filename> on any systems that have &PRODUCT; packages installed.</para>
+                            <para>This file should have one line, which contains:</para>
+                            <programlisting language="Bash">deb http://cloudstack.apt-get.eu/ubuntu precise 4.0</programlisting>
+                            <para>We'll change it to point to the new package repository:</para>
+                            <programlisting language="Bash">deb http://cloudstack.apt-get.eu/ubuntu precise 4.1</programlisting>
+                            <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Now update your apt package list:</para>
+                            <programlisting language="Bash">$ sudo apt-get update</programlisting>
+                        </listitem>
+                        <listitem id="deb-master-22">
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package. This will pull in any other dependencies you need.</para>
+                            <programlisting language="Bash">$ sudo apt-get install cloudstack-management</programlisting>
+                        </listitem>
+                        <listitem id="kvm-agent-deb-22">
+                            <para>You will need to manually install the <filename>cloudstack-agent</filename> package:</para>
+                            <programlisting language="Bash">$ sudo apt-get install cloudstack-agent</programlisting>
+                            <para>During the installation of <filename>cloudstack-agent</filename>, APT will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
+                            <para>When prompted whether you wish to keep your configuration, say Yes.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Verify that the file <filename>/etc/cloudstack/agent/environment.properties</filename> has a line that reads:</para>
+                            <programlisting language="Bash">paths.script=/usr/share/cloudstack-common</programlisting>
+                            <para>If not, add the line.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Restart the agent:</para>
+                            <programlisting language="Bash">
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
+                            </programlisting>
+                        </listitem>
+                        <listitem>
+                            <para>During the upgrade, <filename>log4j-cloud.xml</filename> was simply copied over, so the logs will continue to be added to <filename>/var/log/cloud/agent/agent.log</filename>. There's nothing <emphasis>wrong</emphasis> with this, but if you prefer to be consistent, you can change this by copying over the sample configuration file:</para>
+                            <programlisting language="Bash">
+cd /etc/cloudstack/agent
+mv log4j-cloud.xml.dpkg-dist log4j-cloud.xml
+service cloudstack-agent restart
+                            </programlisting>
+                        </listitem>
+                        <listitem>
+                            <para>Once the agent is running, you can uninstall the old cloud-* packages from your system:</para>
+                            <programlisting language="Bash">sudo dpkg --purge cloud-agent</programlisting>
+                        </listitem> 
+                    </orderedlist>
                 </listitem>
-                <listitem>
+                <listitem id="upgrade-rpm-packages-22">
+                    <para>If you are using CentOS or RHEL, follow this procedure to upgrade your packages. If not, skip to step <xref linkend="correct-components-xml-22" />.</para> 
+                    <note><title>Community Packages</title>
+                        <para>This section assumes you're using the community supplied packages for &PRODUCT;. If you've created your own packages and yum repository, substitute your own URL for the ones used in these examples.</para>
+                    </note>
+                    <orderedlist id="rpmsteps-22">
+                        <listitem>
+                            <para>The first order of business will be to change the yum repository for each system with &PRODUCT; packages. This means all management servers, and any hosts that have the KVM agent. (No changes should be necessary for hosts that are running VMware or Xen.)</para>
+                            <para>Start by opening <filename>/etc/yum.repos.d/cloudstack.repo</filename> on any systems that have &PRODUCT; packages installed.</para>
+                            <para>This file should have content similar to the following:</para>
+                            <programlisting language="Bash">
+[apache-cloudstack]
+name=Apache CloudStack
+baseurl=http://cloudstack.apt-get.eu/rhel/4.0/
+enabled=1
+gpgcheck=0
+                            </programlisting>
+                            <para>If you are using the community provided package repository, change the baseurl to http://cloudstack.apt-get.eu/rhel/4.1/</para>
+                            <para>If you're using your own package repository, change this line to read as appropriate for your 4.1.0 repository.</para>
+                        </listitem>
+                        <listitem id="rpm-master-22">
+                            <para>Now that you have the repository configured, it's time to install the <filename>cloudstack-management</filename> package by upgrading the older <filename>cloud-client</filename> package.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-client</programlisting>
+                        </listitem>
+                        <listitem id="kvm-agent-rpm-22">
+                            <para>For KVM hosts, you will need to upgrade the <filename>cloud-agent</filename> package, similarly installing the new version as <filename>cloudstack-agent</filename>.</para>
+                            <programlisting language="Bash">$ sudo yum upgrade cloud-agent</programlisting>
+                            <para>During the installation of <filename>cloudstack-agent</filename>, the RPM will copy your <filename>agent.properties</filename>, <filename>log4j-cloud.xml</filename>, and <filename>environment.properties</filename> from <filename>/etc/cloud/agent</filename> to <filename>/etc/cloudstack/agent</filename>.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Verify that the file <filename>/etc/cloudstack/agent/environment.properties</filename> has a line that reads:</para>
+                            <programlisting language="Bash">paths.script=/usr/share/cloudstack-common</programlisting>
+                            <para>If not, add the line.</para>
+                        </listitem>
+                        <listitem>
+                            <para>Restart the agent:</para>
+                            <programlisting language="Bash">
+service cloud-agent stop
+killall jsvc
+service cloudstack-agent start
+                            </programlisting>
+                        </listitem>
+                    </orderedlist>
+                </listitem>
+                <listitem id="correct-components-xml-22">
                     <para>If you have made changes to your existing copy of the file components.xml in your
                         previous-version CloudStack installation, the changes will be preserved in the upgrade.
                         However, you need to do the following steps to place these changes in a new version of


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

Posted by ts...@apache.org.
CLOUDSTACK-741: Granular Global Parameters

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/eae22d2f
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/eae22d2f
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/eae22d2f

Branch: refs/heads/marvin_refactor
Commit: eae22d2ffaee68b5d4443cf8ab1b2dfbb339dab3
Parents: 81e1ba3
Author: Harikrishna Patnala <ha...@citrix.com>
Authored: Fri Apr 19 09:27:00 2013 +0530
Committer: Abhinandan Prateek <ap...@apache.org>
Committed: Fri Apr 19 10:36:52 2013 +0530

----------------------------------------------------------------------
 .../api/command/admin/config/ListCfgsByCmd.java    |   24 +++-
 .../api/command/admin/config/UpdateCfgCmd.java     |   22 +++-
 .../api/response/ConfigurationResponse.java        |   12 ++
 .../api/command/test/ListCfgCmdTest.java           |   89 +++++++++++
 .../api/command/test/UpdateCfgCmdTest.java         |  116 +++++++++++++++
 .../datastore/db/StoragePoolDetailsDao.java        |    1 +
 server/src/com/cloud/configuration/Config.java     |   54 ++++++-
 .../cloud/configuration/ConfigurationManager.java  |    2 +-
 .../configuration/ConfigurationManagerImpl.java    |   51 +++++--
 .../cloud/configuration/dao/ConfigurationDao.java  |    1 +
 .../router/VirtualNetworkApplianceManagerImpl.java |    5 +-
 .../src/com/cloud/server/ConfigurationServer.java  |    5 +
 .../com/cloud/server/ConfigurationServerImpl.java  |   93 ++++++++++--
 .../src/com/cloud/server/ManagementServerImpl.java |   24 +++-
 .../storage/dao/StoragePoolDetailsDaoImpl.java     |    9 +
 .../cloud/vpc/MockConfigurationManagerImpl.java    |    5 +-
 test/integration/smoke/test_UpdateCfg.py           |   85 +++++++++++
 17 files changed, 561 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
index aabfd4a..9f34405 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
@@ -23,8 +23,7 @@ import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseListCmd;
 import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.response.ConfigurationResponse;
-import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.*;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Configuration;
@@ -46,6 +45,13 @@ public class ListCfgsByCmd extends BaseListCmd {
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "lists configuration by name")
     private String configName;
 
+    @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
+    private String scope;
+
+    @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope")
+    private Long id;
+
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -58,6 +64,15 @@ public class ListCfgsByCmd extends BaseListCmd {
         return configName;
     }
 
+    public String getScope() {
+        return scope;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+
     @Override
     public Long getPageSizeVal() {
         Long pageSizeVal = 500L;
@@ -85,6 +100,11 @@ public class ListCfgsByCmd extends BaseListCmd {
         for (Configuration cfg : result.first()) {
             ConfigurationResponse cfgResponse = _responseGenerator.createConfigurationResponse(cfg);
             cfgResponse.setObjectName("configuration");
+            if (scope != null) {
+                cfgResponse.setScope(scope);
+            } else {
+                cfgResponse.setScope("global");
+            }
             configResponses.add(cfgResponse);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index ffeb586..074c5a3 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -22,7 +22,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.*;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Configuration;
@@ -43,6 +43,12 @@ public class UpdateCfgCmd extends BaseCmd {
     @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, description="the value of the configuration", length=4095)
     private String value;
 
+    @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description = "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
+    private String scope;
+
+    @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = {ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, AccountResponse.class}, description = "corresponding ID of the scope")
+    private Long id;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -55,6 +61,14 @@ public class UpdateCfgCmd extends BaseCmd {
         return value;
     }
 
+    public String getScope() {
+        return scope;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -75,6 +89,12 @@ public class UpdateCfgCmd extends BaseCmd {
         if (cfg != null) {
             ConfigurationResponse response = _responseGenerator.createConfigurationResponse(cfg);
             response.setResponseName(getCommandName());
+            if (scope != null) {
+                response.setScope(scope);
+                response.setValue(value);
+            } else {
+                response.setScope("global");
+            }
             this.setResponseObject(response);
         } else {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update config");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
index 95b8af2..176c47a 100644
--- a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
@@ -32,9 +32,13 @@ public class ConfigurationResponse extends BaseResponse {
     @SerializedName(ApiConstants.VALUE) @Param(description="the value of the configuration")
     private String value;
 
+    @SerializedName(ApiConstants.SCOPE) @Param(description="scope(zone/cluster/pool/account) of the parameter that needs to be updated")
+    private String scope;
+
     @SerializedName(ApiConstants.DESCRIPTION) @Param(description="the description of the configuration")
     private String description;
 
+
     public String getCategory() {
         return category;
     }
@@ -66,4 +70,12 @@ public class ConfigurationResponse extends BaseResponse {
     public void setDescription(String description) {
         this.description = description;
     }
+
+    public String getScope() {
+        return scope;
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
----------------------------------------------------------------------
diff --git a/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
new file mode 100644
index 0000000..7c05eaf
--- /dev/null
+++ b/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
@@ -0,0 +1,89 @@
+// 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.test;
+
+import com.cloud.configuration.Configuration;
+import com.cloud.configuration.ConfigurationService;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.resource.ResourceService;
+import com.cloud.server.ManagementService;
+import com.cloud.utils.Pair;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
+import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListCfgCmdTest extends TestCase{
+
+    private ListCfgsByCmd listCfgsByCmd;
+    private ManagementService mgr;
+    private ResponseGenerator responseGenerator;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        responseGenerator = Mockito.mock(ResponseGenerator.class);
+        mgr = Mockito.mock(ManagementService.class);
+        listCfgsByCmd = new ListCfgsByCmd();
+    }
+
+    @Test
+    public void testCreateSuccess() {
+
+        Configuration cfg = Mockito.mock(Configuration.class);
+        listCfgsByCmd._mgr = mgr;
+        listCfgsByCmd._responseGenerator = responseGenerator;
+
+
+
+        List<Configuration> configList = new ArrayList<Configuration>();
+        configList.add(cfg);
+
+        Pair<List<? extends Configuration>, Integer> result = new Pair<List<? extends Configuration>, Integer>(configList, 1);
+
+        try {
+            Mockito.when(
+                    mgr.searchForConfigurations(listCfgsByCmd))
+                    .thenReturn(result);
+        }catch (Exception e){
+            Assert.fail("Received exception when success expected " + e.getMessage());
+        }
+        ConfigurationResponse cfgResponse = new ConfigurationResponse();
+        cfgResponse.setName("Test case");
+        Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(cfgResponse);
+
+        listCfgsByCmd.execute();
+        Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
+
+        ListResponse<ConfigurationResponse> actualResponse = (ListResponse<ConfigurationResponse>) listCfgsByCmd.getResponseObject();
+        Assert.assertEquals(cfgResponse, actualResponse.getResponses().get(0));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
----------------------------------------------------------------------
diff --git a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
new file mode 100644
index 0000000..27000cf
--- /dev/null
+++ b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
@@ -0,0 +1,116 @@
+// 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.test;
+
+import com.cloud.configuration.Configuration;
+import com.cloud.configuration.ConfigurationService;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.resource.ResourceService;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
+import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+public class UpdateCfgCmdTest extends TestCase{
+
+    private UpdateCfgCmd updateCfgCmd;
+    private ConfigurationService configService;
+    private ResponseGenerator responseGenerator;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        responseGenerator = Mockito.mock(ResponseGenerator.class);
+        configService = Mockito.mock(ConfigurationService.class);
+        updateCfgCmd = new UpdateCfgCmd();
+    }
+
+    @Test
+    public void testExecuteForEmptyResult() {
+        updateCfgCmd._configService = configService;
+
+        try {
+            updateCfgCmd.execute();
+        } catch (ServerApiException exception) {
+            Assert.assertEquals("Failed to update config",
+                    exception.getDescription());
+        }
+
+    }
+
+    @Test
+    public void testExecuteForNullResult() {
+
+        updateCfgCmd._configService = configService;
+
+        try {
+            Mockito.when(
+                    configService.updateConfiguration(updateCfgCmd))
+                    .thenReturn(null);
+        } catch (InvalidParameterValueException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        try {
+            updateCfgCmd.execute();
+        } catch (ServerApiException exception) {
+            Assert.assertEquals("Failed to update config",
+                    exception.getDescription());
+        }
+
+    }
+
+
+    @Test
+    public void testCreateSuccess() {
+
+        Configuration cfg = Mockito.mock(Configuration.class);
+        updateCfgCmd._configService = configService;
+        updateCfgCmd._responseGenerator = responseGenerator;
+
+        try {
+            Mockito.when(
+                    configService.updateConfiguration(updateCfgCmd))
+                    .thenReturn(cfg);
+        }catch (Exception e){
+            Assert.fail("Received exception when success expected " + e.getMessage());
+        }
+
+        ConfigurationResponse response = new ConfigurationResponse();
+        response.setName("Test case");
+        Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(response);
+
+        updateCfgCmd.execute();
+        Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
+        ConfigurationResponse actualResponse = (ConfigurationResponse) updateCfgCmd.getResponseObject();
+        Assert.assertEquals(response, actualResponse);
+        Assert.assertEquals("updateconfigurationresponse", response.getResponseName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
index be71670..237f235 100644
--- a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
+++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
@@ -25,4 +25,5 @@ public interface StoragePoolDetailsDao extends GenericDao<StoragePoolDetailVO, L
     
     void update(long poolId, Map<String, String> details);
     Map<String, String> getDetails(long poolId);
+    StoragePoolDetailVO findDetail(long poolId, String name);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 2993966..4d1185a 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -16,9 +16,7 @@
 // under the License.
 package com.cloud.configuration;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 
@@ -339,7 +337,7 @@ public enum Config {
 	//disabling lb as cluster sync does not work with distributed cluster
 	AgentLbEnable("Advanced", ManagementServer.class, Boolean.class, "agent.lb.enabled", "false", "If agent load balancing enabled in cluster setup", null),
 	SubDomainNetworkAccess("Advanced", NetworkManager.class, Boolean.class, "allow.subdomain.network.access", "true", "Allow subdomains to use networks dedicated to their parent domain(s)", null),
-	UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", null),
+	UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, "use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", null, ConfigurationParameterScope.zone.toString()),
 	EncodeApiResponse("Advanced", ManagementServer.class, Boolean.class, "encode.api.response", "false", "Do URL encoding for the api response, false by default", null),
 	DnsBasicZoneUpdates("Advanced", NetworkManager.class, String.class, "network.dns.basiczone.updates", "all", "This parameter can take 2 values: all (default) and pod. It defines if DHCP/DNS requests have to be send to all dhcp servers in cloudstack, or only to the one in the same pod", "all,pod"),
 
@@ -412,6 +410,35 @@ public enum Config {
     private final String _defaultValue;
     private final String _description;
     private final String _range;
+    private final String _scope; // Parameter can be at different levels (Zone/cluster/pool/account), by default every parameter is at global
+
+    public static enum ConfigurationParameterScope {
+        global,
+        zone,
+        cluster,
+        pool,
+        account
+    }
+
+    private static final HashMap<String, List<Config>> _scopeLevelConfigsMap = new HashMap<String, List<Config>>();
+    static {
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.zone.toString(), new ArrayList<Config>());
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.cluster.toString(), new ArrayList<Config>());
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.pool.toString(), new ArrayList<Config>());
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.account.toString(), new ArrayList<Config>());
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.global.toString(), new ArrayList<Config>());
+
+        for (Config c : Config.values()) {
+            //Creating group of parameters per each level (zone/cluster/pool/account)
+            StringTokenizer tokens = new StringTokenizer(c.getScope(), ",");
+            while (tokens.hasMoreTokens()) {
+                String scope = tokens.nextToken().trim();
+                List<Config> currentConfigs = _scopeLevelConfigsMap.get(scope);
+                currentConfigs.add(c);
+                _scopeLevelConfigsMap.put(scope, currentConfigs);
+            }
+        }
+    }
 
     private static final HashMap<String, List<Config>> _configs = new HashMap<String, List<Config>>();
     static {
@@ -447,6 +474,17 @@ public enum Config {
     	_defaultValue = defaultValue;
     	_description = description;
     	_range = range;
+        _scope = ConfigurationParameterScope.global.toString();
+    }
+    private Config(String category, Class<?> componentClass, Class<?> type, String name, String defaultValue, String description, String range, String scope) {
+        _category = category;
+        _componentClass = componentClass;
+        _type = type;
+        _name = name;
+        _defaultValue = defaultValue;
+        _description = description;
+        _range = range;
+        _scope = scope;
     }
 
     public String getCategory() {
@@ -473,6 +511,10 @@ public enum Config {
         return _componentClass;
     }
 
+    public String getScope() {
+        return _scope;
+    }
+
     public String getComponent() {
     	if (_componentClass == ManagementServer.class) {
             return "management-server";
@@ -530,4 +572,8 @@ public enum Config {
     	}
     	return categories;
     }
+
+    public static List<Config> getConfigListByScope(String scope) {
+        return _scopeLevelConfigsMap.get(scope);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java
index afaf0d6..738c5ba 100755
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -60,7 +60,7 @@ public interface ConfigurationManager extends ConfigurationService, Manager {
      * @param name
      * @param value
      */
-    void updateConfiguration(long userId, String name, String category, String value);
+    void updateConfiguration(long userId, String name, String category, String value, String scope, Long id);
 
     /**
      * Creates a new service offering

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 4fc2db7..d142ca6 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -39,6 +39,7 @@ import javax.naming.NamingException;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
 
+import com.cloud.dc.dao.*;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.api.ApiConstants.LDAPParams;
 import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
@@ -78,20 +79,13 @@ import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.DataCenterIpAddressVO;
 import com.cloud.dc.DataCenterLinkLocalIpAddressVO;
 import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.DcDetailVO;
 import com.cloud.dc.HostPodVO;
 import com.cloud.dc.Pod;
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.Vlan;
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.AccountVlanMapDao;
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.dc.dao.DataCenterIpAddressDao;
-import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao;
-import com.cloud.dc.dao.HostPodDao;
-import com.cloud.dc.dao.PodVlanMapDao;
-import com.cloud.dc.dao.VlanDao;
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
@@ -188,6 +182,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
     @Inject
     DataCenterDao _zoneDao;
     @Inject
+    DcDetailsDao _zoneDetailsDao;
+    @Inject
     DomainDao _domainDao;
     @Inject
     SwiftDao _swiftDao;
@@ -327,15 +323,37 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
 
     @Override
     @DB
-    public void updateConfiguration(long userId, String name, String category, String value) {
+    public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) {
 
-        String validationMsg = validateConfigurationValue(name, value);
+        String validationMsg = validateConfigurationValue(name, value, scope);
 
         if (validationMsg != null) {
             s_logger.error("Invalid configuration option, name: " + name + ", value:" + value);
             throw new InvalidParameterValueException(validationMsg);
         }
 
+        // If scope of the parameter is given then it needs to be updated in the corresponding details table,
+        // if scope is mentioned as global or not mentioned then it is normal global parameter updation
+        if (scope != null && !scope.isEmpty() && !Config.ConfigurationParameterScope.global.toString().equalsIgnoreCase(scope)) {
+            if (Config.ConfigurationParameterScope.zone.toString().equalsIgnoreCase(scope)) {
+                DataCenterVO zone = _zoneDao.findById(resourceId);
+                if (zone == null) {
+                    throw new InvalidParameterValueException("unable to find zone by id " + resourceId);
+                }
+                DcDetailVO dcDetailVO = _zoneDetailsDao.findDetail(resourceId, name.toLowerCase());
+                if (dcDetailVO == null) {
+                    dcDetailVO = new DcDetailVO(dcDetailVO.getId(), name, value);
+                    _zoneDetailsDao.persist(dcDetailVO);
+                } else {
+                    dcDetailVO.setValue(value);
+                    _zoneDetailsDao.update(resourceId, dcDetailVO);
+                }
+            } else {
+                s_logger.error("TO Do for the remaining levels (cluster/pool/account)");
+                throw new InvalidParameterValueException("The scope "+ scope +" yet to be implemented");
+            }
+        }
+
         // Execute all updates in a single transaction
         Transaction txn = Transaction.currentTxn();
         txn.start();
@@ -440,6 +458,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         Long userId = UserContext.current().getCallerUserId();
         String name = cmd.getCfgName();
         String value = cmd.getValue();
+        String scope = cmd.getScope();
+        Long id = cmd.getId();
         UserContext.current().setEventDetails(" Name: " + name + " New Value: " + (((name.toLowerCase()).contains("password")) ? "*****" :
                 (((value == null) ? "" : value))));
         // check if config value exists
@@ -456,7 +476,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
             value = null;
         }
 
-        updateConfiguration(userId, name, config.getCategory(), value);
+        updateConfiguration(userId, name, config.getCategory(), value, scope, id);
         String updatedValue = _configDao.getValue(name);
         if ((value == null && updatedValue == null) || updatedValue.equalsIgnoreCase(value)) {
             return _configDao.findByName(name);
@@ -466,13 +486,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
         }
     }
 
-    private String validateConfigurationValue(String name, String value) {
+    private String validateConfigurationValue(String name, String value, String scope) {
 
         Config c = Config.getConfig(name);
         if (c == null) {
             s_logger.error("Missing configuration variable " + name + " in configuration table");
             return "Invalid configuration variable.";
         }
+        String configScope = c.getScope();
+        if (scope != null && !scope.isEmpty()) {
+            if (!configScope.contains(scope)) {
+                s_logger.error("Invalid scope " + scope + " for the parameter " + name);
+                return "Invalid scope for the parameter.";
+            }
+        }
 
         Class<?> type = c.getType();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/dao/ConfigurationDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDao.java b/server/src/com/cloud/configuration/dao/ConfigurationDao.java
index c86c024..2b09901 100644
--- a/server/src/com/cloud/configuration/dao/ConfigurationDao.java
+++ b/server/src/com/cloud/configuration/dao/ConfigurationDao.java
@@ -17,6 +17,7 @@
 package com.cloud.configuration.dao;
 
 import java.util.Map;
+import java.util.List;
 
 import com.cloud.configuration.ConfigurationVO;
 import com.cloud.utils.db.GenericDao;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index ab91059..4c7bc75 100755
--- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -40,6 +40,7 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.server.ConfigurationServer;
 import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
@@ -286,6 +287,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
     @Inject
     ConfigurationManager _configMgr;
     @Inject
+    ConfigurationServer _configServer;
+    @Inject
     ServiceOfferingDao _serviceOfferingDao = null;
     @Inject
     UserVmDao _userVmDao;
@@ -2094,7 +2097,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V
 
             boolean useExtDns = !dnsProvided;
             /* For backward compatibility */
-            String use_external_dns =  _configDao.getValue(Config.UseExternalDnsServers.key());
+            String use_external_dns = _configServer.getConfigValue(Config.UseExternalDnsServers.key(), Config.ConfigurationParameterScope.zone.toString(), dc.getId());
             if (use_external_dns != null && use_external_dns.equals("true")) {
                 useExtDns = true;
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ConfigurationServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServer.java b/server/src/com/cloud/server/ConfigurationServer.java
index f441b1f..c1306d5 100644
--- a/server/src/com/cloud/server/ConfigurationServer.java
+++ b/server/src/com/cloud/server/ConfigurationServer.java
@@ -16,6 +16,9 @@
 // under the License.
 package com.cloud.server;
 
+import java.util.List;
+
+import com.cloud.configuration.ConfigurationVO;
 import com.cloud.exception.InternalErrorException;
 
 /**
@@ -30,4 +33,6 @@ public interface ConfigurationServer {
      */
     public void persistDefaultValues() throws InternalErrorException;
     public void updateKeyPairs();
+    public String getConfigValue(String name, String scope, Long resourceId);
+    public List<ConfigurationVO> getConfigListByScope(String scope, Long resourceId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ConfigurationServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java
index c4da1ab..cd890ce 100755
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -36,28 +36,29 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.regex.Pattern;
+import java.util.StringTokenizer;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.configuration.*;
+import com.cloud.dc.*;
+import com.cloud.dc.dao.DcDetailsDao;
+import com.cloud.user.*;
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import com.cloud.configuration.Config;
-import com.cloud.configuration.ConfigurationVO;
-import com.cloud.configuration.Resource;
 import com.cloud.configuration.Resource.ResourceOwnerType;
 import com.cloud.configuration.Resource.ResourceType;
-import com.cloud.configuration.ResourceCountVO;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.configuration.dao.ResourceCountDao;
 import com.cloud.dc.DataCenter.NetworkType;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.HostPodVO;
-import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.HostPodDao;
 import com.cloud.dc.dao.VlanDao;
@@ -91,9 +92,6 @@ import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.test.IPRangeConfig;
-import com.cloud.user.Account;
-import com.cloud.user.AccountVO;
-import com.cloud.user.User;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.PasswordGenerator;
 import com.cloud.utils.PropertiesUtil;
@@ -127,6 +125,11 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
     @Inject private ResourceCountDao _resourceCountDao;
     @Inject private NetworkOfferingServiceMapDao _ntwkOfferingServiceMapDao;
     @Inject private IdentityDao _identityDao;
+    @Inject private DcDetailsDao _dcDetailsDao;
+    @Inject private ClusterDetailsDao _clusterDetailsDao;
+    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    @Inject private AccountDetailsDao _accountDetailsDao;
+
 
     public ConfigurationServerImpl() {
     	setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP);
@@ -672,6 +675,76 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
         }
     }
 
+    @Override
+    public String getConfigValue(String name, String scope, Long resourceId) {
+        // If either of scope or resourceId is null then return global config value otherwise return value at the scope
+        Config c = Config.getConfig(name);
+        if (c == null) {
+            throw new CloudRuntimeException("Missing configuration variable " + name + " in configuration table");
+        }
+        String configScope = c.getScope();
+        if (scope != null && !scope.isEmpty()) {
+            if (!configScope.contains(scope)) {
+                throw new CloudRuntimeException("Invalid scope " + scope + " for the parameter " + name );
+            }
+            if (resourceId != null) {
+                switch (Config.ConfigurationParameterScope.valueOf(scope)) {
+                    case zone:      DataCenterVO zone = _zoneDao.findById(resourceId);
+                                    if (zone == null) {
+                                        throw new InvalidParameterValueException("unable to find zone by id " + resourceId);
+                                    }
+                                    DcDetailVO dcDetailVO = _dcDetailsDao.findDetail(resourceId, name);
+                                    if (dcDetailVO != null && dcDetailVO.getValue() != null) {
+                                        return dcDetailVO.getValue();
+                                    } break;
+
+                    case cluster:   ClusterDetailsVO cluster = _clusterDetailsDao.findById(resourceId);
+                                    if (cluster == null) {
+                                        throw new InvalidParameterValueException("unable to find cluster by id " + resourceId);
+                                    }
+                                    ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(resourceId, name);
+                                    if (clusterDetailsVO != null && clusterDetailsVO.getValue() != null) {
+                                        return clusterDetailsVO.getValue();
+                                    } break;
+
+                    case pool:      StoragePoolDetailVO pool = _storagePoolDetailsDao.findById(resourceId);
+                                    if (pool == null) {
+                                        throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId);
+                                    }
+                                    StoragePoolDetailVO storagePoolDetailVO = _storagePoolDetailsDao.findDetail(resourceId, name);
+                                    if (storagePoolDetailVO != null && storagePoolDetailVO.getValue() != null) {
+                                        return storagePoolDetailVO.getValue();
+                                    } break;
+
+                    case account:   AccountDetailVO account = _accountDetailsDao.findById(resourceId);
+                                    if (account == null) {
+                                        throw new InvalidParameterValueException("unable to find account by id " + resourceId);
+                                    }
+                                    AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(resourceId, name);
+                                    if (accountDetailVO != null && accountDetailVO.getValue() != null) {
+                                        return accountDetailVO.getValue();
+                                    } break;
+                    default:
+                }
+            }
+        }
+        return _configDao.getValue(name);
+    }
+
+    @Override
+    public List<ConfigurationVO> getConfigListByScope(String scope, Long resourceId) {
+
+        // Getting the list of parameters defined at the scope
+        List<Config> configList = Config.getConfigListByScope(scope);
+        List<ConfigurationVO> configVOList = new ArrayList<ConfigurationVO>();
+        for (Config param:configList){
+            ConfigurationVO configVo = _configDao.findByName(param.toString());
+            configVo.setValue(getConfigValue(param.toString(), scope, resourceId));
+            configVOList.add(configVo);
+        }
+        return configVOList;
+    }
+
     private void writeKeyToDisk(String key, String keyPath) {
         File keyfile = new File(keyPath);
         if (!keyfile.exists()) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 98f789a..db8db8a 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -44,6 +44,7 @@ import javax.crypto.spec.SecretKeySpec;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.configuration.*;
 import com.cloud.storage.dao.*;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ApiConstants;
@@ -106,10 +107,6 @@ import com.cloud.capacity.CapacityVO;
 import com.cloud.capacity.dao.CapacityDao;
 import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
 import com.cloud.cluster.ClusterManager;
-import com.cloud.configuration.Config;
-import com.cloud.configuration.Configuration;
-import com.cloud.configuration.ConfigurationManager;
-import com.cloud.configuration.ConfigurationVO;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.consoleproxy.ConsoleProxyManagementState;
 import com.cloud.consoleproxy.ConsoleProxyManager;
@@ -381,6 +378,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
     @Inject
     S3Manager _s3Mgr;
 
+    @Inject
+    ConfigurationServer _configServer;
+
     private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
     private final ScheduledExecutorService _alertExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker"));
     private KeystoreManager _ksMgr;
@@ -1038,6 +1038,22 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         Object name = cmd.getConfigName();
         Object category = cmd.getCategory();
         Object keyword = cmd.getKeyword();
+        Long id = cmd.getId();
+        String scope = cmd.getScope();
+
+        if (scope!= null && !scope.isEmpty()) {
+            // getting the list of parameters at requested scope
+            try {
+                Config.ConfigurationParameterScope.valueOf(scope.toLowerCase());
+            } catch (Exception e ) {
+                throw new InvalidParameterValueException("Invalid scope " + scope + " while listing configuration parameters");
+            }
+            if (id == null) {
+                throw new InvalidParameterValueException("Invalid id null, id is needed corresponding to the scope");
+            }
+            List<ConfigurationVO> configList = _configServer.getConfigListByScope(scope, id);
+            return new Pair<List<? extends Configuration>, Integer>(configList, configList.size());
+        }
 
         if (keyword != null) {
             SearchCriteria<ConfigurationVO> ssc = _configDao.createSearchCriteria();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
index 0d797ed..a0d5d0e 100644
--- a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
+++ b/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
@@ -72,4 +72,13 @@ public class StoragePoolDetailsDaoImpl extends GenericDaoBase<StoragePoolDetailV
     	
     	return detailsMap;
     }
+
+    @Override
+    public StoragePoolDetailVO findDetail(long poolId, String name) {
+        SearchCriteria<StoragePoolDetailVO> sc = PoolSearch.create();
+        sc.setParameters("pool", poolId);
+        sc.setParameters("name", name);
+
+        return findOneIncludingRemovedBy(sc);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index 9443815..6cda294 100755
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -25,6 +25,7 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 import javax.naming.NamingException;
 
+import com.cloud.configuration.ConfigurationVO;
 import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
 import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
 import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
@@ -425,9 +426,9 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
      * @see com.cloud.configuration.ConfigurationManager#updateConfiguration(long, java.lang.String, java.lang.String, java.lang.String)
      */
     @Override
-    public void updateConfiguration(long userId, String name, String category, String value) {
+    public void updateConfiguration(long userId, String name, String category, String value, String scope, Long resourceId) {
         // TODO Auto-generated method stub
-        
+
     }
 
     /* (non-Javadoc)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/test/integration/smoke/test_UpdateCfg.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_UpdateCfg.py b/test/integration/smoke/test_UpdateCfg.py
new file mode 100644
index 0000000..be501b9
--- /dev/null
+++ b/test/integration/smoke/test_UpdateCfg.py
@@ -0,0 +1,85 @@
+# 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.
+""" P1 tests for updating the granular Configuration parameter with scope and resource id provided.
+"""
+#Import Local Modules
+import marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from nose.plugins.attrib import attr
+#Import System modules
+import unittest
+import hashlib
+import random
+
+class TestUpdateConfigWithScope(cloudstackTestCase):
+    """
+    This test updates the value of a configuration parameter
+    which is at zone level(scope)
+    """
+    def setUp(self):
+        """
+        CloudStack internally saves its passwords in md5 form and that is how we
+        specify it in the API. Python's hashlib library helps us to quickly hash
+        strings as follows
+        """
+        mdf = hashlib.md5()
+        mdf.update('password')
+        mdf_pass = mdf.hexdigest()
+
+        self.apiClient = self.testClient.getApiClient() #Get ourselves an API client
+
+
+
+    def test_UpdateConfigParamWithScope(self):
+
+        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
+        updateConfigurationCmd.name = "use.external.dns"
+        updateConfigurationCmd.value = "true"
+        updateConfigurationCmd.scope = "zone"
+        updateConfigurationCmd.id = 1
+
+        updateConfigurationResponse = self.apiClient.updateConfiguration(updateConfigurationCmd)
+        self.debug("updated the parameter %s with value %s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
+
+        listConfigurationsCmd = listConfigurations.listConfigurationsCmd()
+        listConfigurationsCmd.cfgName = updateConfigurationResponse.name
+        listConfigurationsCmd.scope = "zone"
+        listConfigurationsCmd.id = 1
+        listConfigurationsResponse = self.apiClient.listConfigurations(listConfigurationsCmd)
+
+        self.assertNotEqual(len(listConfigurationsResponse), 0, "Check if the list API \
+                            returns a non-empty response")
+
+        configParam = listConfigurationsResponse[0]
+
+        self.assertEqual(configParam.value, updateConfigurationResponse.value, "Check if the update API returned \
+                         is the same as the one we got in the list API")
+
+
+    def tearDown(self):
+
+        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
+        updateConfigurationCmd.name = "use.external.dns"
+        updateConfigurationCmd.value = "false"
+        updateConfigurationCmd.scope = "zone"
+        updateConfigurationCmd.id = 1
+        self.apiClient.updateConfiguration(updateConfigurationCmd)