You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/12/19 03:23:17 UTC

[3/3] git commit: updated refs/heads/4.3 to 15403a1

add xenserver 6.2.0 hotfix support, to optimize vdi copy

add xenserver hot fix


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

Branch: refs/heads/4.3
Commit: 15403a1f294bec2f47bd44549594215074fb6c86
Parents: 3ce63be
Author: edison <su...@gmail.com>
Authored: Tue Dec 17 16:11:51 2013 -0800
Committer: Edison Su <su...@gmail.com>
Committed: Wed Dec 18 18:22:52 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/vm/VirtualMachineName.java    |  13 +
 core/src/com/cloud/host/HostInfo.java           |   1 +
 .../cloudstack/storage/command/CopyCommand.java |  12 +
 .../cloudstack/storage/to/SnapshotObjectTO.java |  19 +-
 .../src/com/xensource/xenapi/Event.java         |  15 +
 .../src/com/xensource/xenapi/Types.java         |  50 ++
 .../src/com/xensource/xenapi/VDI.java           |  29 +-
 .../subsystem/api/storage/EndPointSelector.java |   2 +
 .../orchestration/VolumeOrchestrator.java       |   8 +-
 .../datastore/db/SnapshotDataStoreDao.java      |   2 +
 .../motion/AncientDataMotionStrategy.java       |  16 +-
 .../snapshot/XenserverSnapshotStrategy.java     |  30 +-
 .../endpoint/DefaultEndPointSelector.java       |  49 ++
 .../image/db/SnapshotDataStoreDaoImpl.java      |  32 +-
 .../src/com/cloud/hypervisor/XenServerGuru.java |  40 +-
 .../xen/discoverer/XcpServerDiscoverer.java     |  48 +-
 .../xen/resource/CitrixResourceBase.java        | 810 +++---------------
 .../xen/resource/XenServerPoolVms.java          |   6 +-
 .../xen/resource/XenServerStorageProcessor.java |   8 +-
 .../xen/resource/Xenserver625Resource.java      | 112 +++
 .../resource/Xenserver625StorageProcessor.java  | 822 +++++++++++++++++++
 .../xenserver/XenServerResourceNewBase.java     | 340 ++++++++
 .../xenserver/xenserver62/cloud-plugin-storage  | 301 +++++++
 .../vm/hypervisor/xenserver/xenserver62/patch   |  74 ++
 server/src/com/cloud/configuration/Config.java  |   1 +
 25 files changed, 2105 insertions(+), 735 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/api/src/com/cloud/vm/VirtualMachineName.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/VirtualMachineName.java b/api/src/com/cloud/vm/VirtualMachineName.java
index 1279fd6..49cb40b 100755
--- a/api/src/com/cloud/vm/VirtualMachineName.java
+++ b/api/src/com/cloud/vm/VirtualMachineName.java
@@ -25,6 +25,19 @@ import com.cloud.dc.Vlan;
  */
 public class VirtualMachineName {
     public static final String SEPARATOR = "-";
+
+    public static boolean isValidCloudStackVmName(String name, String instance) {
+        String[] parts = name.split(SEPARATOR);
+        if (parts.length <= 1) {
+            return false;
+        }
+
+        if (!parts[parts.length - 1].equals(instance)) {
+            return false;
+        }
+
+        return true;
+    }
     
     public static String getVnetName(long vnetId) {
         StringBuilder vnet = new StringBuilder();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/core/src/com/cloud/host/HostInfo.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/host/HostInfo.java b/core/src/com/cloud/host/HostInfo.java
index af929e3..3364e8f 100644
--- a/core/src/com/cloud/host/HostInfo.java
+++ b/core/src/com/cloud/host/HostInfo.java
@@ -21,5 +21,6 @@ public final class HostInfo {
 	public static final String HOST_OS = "Host.OS"; //Fedora, XenServer, Ubuntu, etc
 	public static final String HOST_OS_VERSION = "Host.OS.Version"; //12, 5.5, 9.10, etc
 	public static final String HOST_OS_KERNEL_VERSION = "Host.OS.Kernel.Version"; //linux-2.6.31 etc
+    public static final String XS620_SNAPSHOT_HOTFIX = "xs620_snapshot_hotfix";
 	
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
index e9ec0b3..a4ab070 100644
--- a/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
+++ b/core/src/org/apache/cloudstack/storage/command/CopyCommand.java
@@ -16,6 +16,9 @@
 // under the License.
 package org.apache.cloudstack.storage.command;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.to.DataTO;
 
@@ -24,6 +27,7 @@ public final class CopyCommand extends Command implements StorageSubSystemComman
     private DataTO destTO;
     private DataTO cacheTO;
     boolean executeInSequence = false;
+    Map<String, String> options = new HashMap<String, String>();
 
 
     public CopyCommand(DataTO srcData, DataTO destData, int timeout, boolean executeInSequence) {
@@ -67,4 +71,12 @@ public final class CopyCommand extends Command implements StorageSubSystemComman
         return this.getWait() * 1000;
     }
 
+    public void setOptions(Map<String, String> options) {
+        this.options = options;
+    }
+
+    public Map<String, String> getOptions() {
+        return options;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index 34e977c..55e34e4 100644
--- a/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/core/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -16,13 +16,16 @@
 // under the License.
 package org.apache.cloudstack.storage.to;
 
+import java.util.ArrayList;
+
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
+import org.apache.commons.lang.ArrayUtils;
 
 import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
-import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 
 public class SnapshotObjectTO implements DataTO {
     private String path;
@@ -34,6 +37,8 @@ public class SnapshotObjectTO implements DataTO {
     private HypervisorType hypervisorType;
     private long id;
     private boolean quiescevm;
+    private String[] parents;
+
 
     public SnapshotObjectTO() {
 
@@ -49,9 +54,17 @@ public class SnapshotObjectTO implements DataTO {
         }
 
         SnapshotInfo parentSnapshot = snapshot.getParent();
+        ArrayList<String> parentsArry = new ArrayList<String>();
         if (parentSnapshot != null) {
             this.parentSnapshotPath = parentSnapshot.getPath();
+            while(parentSnapshot != null) {
+                parentsArry.add(parentSnapshot.getPath());
+                parentSnapshot = parentSnapshot.getParent();
+            }
+            parents =  parentsArry.toArray(new String[parentsArry.size()]);
+            ArrayUtils.reverse(parents);
         }
+
         this.dataStore = snapshot.getDataStore().getTO();
         this.setName(snapshot.getName());
         this.hypervisorType = snapshot.getHypervisorType();
@@ -139,6 +152,10 @@ public class SnapshotObjectTO implements DataTO {
         this.quiescevm = quiescevm;
     }
 
+    public String[] getParents() {
+        return parents;
+    }
+
     @Override
     public String toString() {
         return new StringBuilder("SnapshotTO[datastore=").append(dataStore).append("|volume=").append(volume).append("|path")

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/deps/XenServerJava/src/com/xensource/xenapi/Event.java
----------------------------------------------------------------------
diff --git a/deps/XenServerJava/src/com/xensource/xenapi/Event.java b/deps/XenServerJava/src/com/xensource/xenapi/Event.java
index 3574cd1..e1273a5 100644
--- a/deps/XenServerJava/src/com/xensource/xenapi/Event.java
+++ b/deps/XenServerJava/src/com/xensource/xenapi/Event.java
@@ -301,4 +301,19 @@ public class Event extends XenAPIObject {
             return Types.toString(result);
     }
 
+    public static Map properFrom(Connection c, Set<String> classes, String token, Double timeout) throws BadServerResponse, XenAPIException, XmlRpcException,
+            Types.SessionNotRegistered,
+            Types.EventsLost {
+        String method_call = "event.from";
+        String session = c.getSessionReference();
+        Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(classes), Marshalling.toXMLRPC(token), Marshalling.toXMLRPC(timeout)};
+        Map response = c.dispatch(method_call, method_params);
+        Object result = response.get("Value");
+        Map value = (Map)result;
+        Map<String, Object> from = new HashMap<String, Object>();
+        from.put("token", value.get("token"));
+        from.put("events", Types.toSetOfEventRecord(value.get("events")));
+        return from;
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/deps/XenServerJava/src/com/xensource/xenapi/Types.java
----------------------------------------------------------------------
diff --git a/deps/XenServerJava/src/com/xensource/xenapi/Types.java b/deps/XenServerJava/src/com/xensource/xenapi/Types.java
index bde887a..36e38c1 100644
--- a/deps/XenServerJava/src/com/xensource/xenapi/Types.java
+++ b/deps/XenServerJava/src/com/xensource/xenapi/Types.java
@@ -1278,6 +1278,17 @@ public class Types
                 String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : "";
                 throw new Types.CrlNameInvalid(p1);
             }
+            if (ErrorDescription[0].equals("VDI_NOT_SPARSE"))
+            {
+                String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : "";
+                throw new Types.VdiNotSparse(p1);
+            }
+            if (ErrorDescription[0].equals("VDI_TOO_SMALL"))
+            {
+                String p1 = ErrorDescription.length > 1 ? ErrorDescription[1] : "";
+                String p2 = ErrorDescription.length > 2 ? ErrorDescription[2] : "";
+                throw new Types.VdiTooSmall(p1, p2);
+            }
             if (ErrorDescription[0].equals("HOST_POWER_ON_MODE_DISABLED"))
             {
                 throw new Types.HostPowerOnModeDisabled();
@@ -7574,6 +7585,45 @@ public class Types
     }
 
     /**
+     * The VDI is too small. Please resize it to at least the minimum size.
+     */
+    public static class VdiTooSmall extends XenAPIException {
+        public final String vdi;
+        public final String minimumSize;
+
+        /**
+         * Create a new VdiTooSmall
+         *
+         * @param vdi
+         * @param minimumSize
+         */
+        public VdiTooSmall(String vdi, String minimumSize) {
+            super("The VDI is too small. Please resize it to at least the minimum size.");
+            this.vdi = vdi;
+            this.minimumSize = minimumSize;
+        }
+
+    }
+
+    /**
+     * The VDI is not stored using a sparse format. It is not possible to query and manipulate only the changed blocks (or 'block differences' or 'disk deltas') between two VDIs. Please select a VDI which uses a sparse-aware technology such as VHD.
+     */
+    public static class VdiNotSparse extends XenAPIException {
+        public final String vdi;
+
+        /**
+         * Create a new VdiNotSparse
+         *
+         * @param vdi
+         */
+        public VdiNotSparse(String vdi) {
+            super("The VDI is not stored using a sparse format. It is not possible to query and manipulate only the changed blocks (or 'block differences' or 'disk deltas') between two VDIs. Please select a VDI which uses a sparse-aware technology such as VHD.");
+            this.vdi = vdi;
+        }
+
+    }
+
+    /**
      * The hosts in this pool are not homogeneous.
      */
     public static class HostsNotHomogeneous extends XenAPIException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/deps/XenServerJava/src/com/xensource/xenapi/VDI.java
----------------------------------------------------------------------
diff --git a/deps/XenServerJava/src/com/xensource/xenapi/VDI.java b/deps/XenServerJava/src/com/xensource/xenapi/VDI.java
index 4ea9daf..167c5a0 100644
--- a/deps/XenServerJava/src/com/xensource/xenapi/VDI.java
+++ b/deps/XenServerJava/src/com/xensource/xenapi/VDI.java
@@ -1594,15 +1594,38 @@ public class VDI extends XenAPIObject {
     }
 
     /**
+     * Copy either a full VDI or the block differences between two VDIs into either a fresh VDI or an existing VDI.
+     *
+     * @param sr The destination SR (only required if the destination VDI is not specified
+     * @param baseVdi The base VDI (only required if copying only changed blocks, by default all blocks will be copied)
+     * @param intoVdi The destination VDI to copy blocks into (if omitted then a destination SR must be provided and a fresh VDI will be created)
+     * @return Task
+     */
+    public Task copyAsync2(Connection c, SR sr, VDI baseVdi, VDI intoVdi) throws
+            BadServerResponse,
+            XenAPIException,
+            XmlRpcException,
+            Types.VdiReadonly,
+            Types.VdiTooSmall,
+            Types.VdiNotSparse {
+        String method_call = "Async.VDI.copy";
+        String session = c.getSessionReference();
+        Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(this.ref), Marshalling.toXMLRPC(sr), Marshalling.toXMLRPC(baseVdi), Marshalling.toXMLRPC(intoVdi)};
+        Map response = c.dispatch(method_call, method_params);
+        Object result = response.get("Value");
+        return Types.toTask(result);
+    }
+
+    /**
      * Make a fresh VDI in the specified SR and copy the supplied VDI's data to the new disk
      *
      * @param sr The destination SR
      * @return Task
      */
     public Task copyAsync(Connection c, SR sr) throws
-       BadServerResponse,
-       XenAPIException,
-       XmlRpcException {
+            BadServerResponse,
+            XenAPIException,
+            XmlRpcException {
         String method_call = "Async.VDI.copy";
         String session = c.getSessionReference();
         Object[] method_params = {Marshalling.toXMLRPC(session), Marshalling.toXMLRPC(this.ref), Marshalling.toXMLRPC(sr)};

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
index b812f6e..8f5921d 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
@@ -30,4 +30,6 @@ public interface EndPointSelector {
     List<EndPoint> selectAll(DataStore store);
 
     EndPoint select(Scope scope, Long storeId);
+
+    EndPoint selectHypervisorHost(Scope scope);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 41a3f29..ebd8709 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -424,10 +424,6 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
 
         StoragePool pool = null;
 
-        if (diskOffering != null && diskOffering.isCustomized()) {
-            diskOffering.setDiskSize(size);
-        }
-
         DiskProfile dskCh = null;
         if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
             dskCh = createDiskCharacteristics(volume, template, dc, offering);
@@ -435,6 +431,10 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
             dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
         }
 
+        if (diskOffering != null && diskOffering.isCustomized()) {
+            dskCh.setSize(size);
+        }
+
         dskCh.setHyperType(hyperType);
 
         final HashSet<StoragePool> avoidPools = new HashSet<StoragePool>(avoids);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
index dfa03ad..666d2ce 100644
--- a/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
+++ b/engine/schema/src/org/apache/cloudstack/storage/datastore/db/SnapshotDataStoreDao.java
@@ -50,4 +50,6 @@ StateDao<ObjectInDataStoreStateMachine.State, ObjectInDataStoreStateMachine.Even
     List<SnapshotDataStoreVO> listOnCache(long snapshotId);
 
     void updateStoreRoleToCache(long storeId);
+
+    SnapshotDataStoreVO findLatestSnapshotForVolume(Long volumeId, DataStoreRole role);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 8e65e80..1cd94ef 100644
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -18,13 +18,11 @@
  */
 package org.apache.cloudstack.storage.motion;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.inject.Inject;
 
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
 import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
@@ -46,6 +44,8 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.MigrateVolumeAnswer;
@@ -481,6 +481,14 @@ AncientDataMotionStrategy implements DataMotionStrategy {
                 Integer.parseInt(Config.BackupSnapshotWait.getDefaultValue()));
 
         DataObject cacheData = null;
+        SnapshotInfo snapshotInfo = (SnapshotInfo)srcData;
+        Object payload = snapshotInfo.getPayload();
+        Boolean fullSnapshot = true;
+        if (payload != null) {
+            fullSnapshot = (Boolean)payload;
+        }
+        Map<String, String> options = new HashMap<String, String>();
+        options.put("fullSnapshot", fullSnapshot.toString());
         Answer answer = null;
         try {
             if (needCacheStorage(srcData, destData)) {
@@ -489,6 +497,7 @@ AncientDataMotionStrategy implements DataMotionStrategy {
 
                 CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
                 cmd.setCacheTO(cacheData.getTO());
+                cmd.setOptions(options);
                 EndPoint ep = selector.select(srcData, destData);
                 if (ep == null) {
                     String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";
@@ -499,6 +508,7 @@ AncientDataMotionStrategy implements DataMotionStrategy {
                 }
             } else {
                 CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
+                cmd.setOptions(options);
                 EndPoint ep = selector.select(srcData, destData);
                 if (ep == null) {
                     String errMsg = "No remote endpoint to send command, check if host or ssvm is down?";

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
index b5a11d8..ae48fe4 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
@@ -21,10 +21,6 @@ import java.util.List;
 
 import javax.inject.Inject;
 
-import com.cloud.storage.*;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
 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.ObjectInDataStoreStateMachine.Event;
@@ -40,8 +36,15 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
 
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.storage.CreateSnapshotPayload;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Volume;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.utils.NumbersUtil;
@@ -103,21 +106,16 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
 
         // determine full snapshot backup or not
 
-        boolean fullBackup = false;
-
-        if (parentSnapshot != null) {
+        boolean fullBackup = true;
+        SnapshotDataStoreVO parentSnapshotOnBackupStore = snapshotStoreDao.findLatestSnapshotForVolume(snapshot.getVolumeId(), DataStoreRole.Image);
+        if (parentSnapshotOnBackupStore != null) {
             int _deltaSnapshotMax = NumbersUtil.parseInt(configDao.getValue("snapshot.delta.max"),
                     SnapshotManager.DELTAMAX);
             int deltaSnap = _deltaSnapshotMax;
 
             int i;
-            SnapshotDataStoreVO parentSnapshotOnBackupStore = null;
+
             for (i = 1; i < deltaSnap; i++) {
-                parentSnapshotOnBackupStore = snapshotStoreDao.findBySnapshot(parentSnapshot.getId(),
-                        DataStoreRole.Image);
-                if (parentSnapshotOnBackupStore == null) {
-                    break;
-                }
                 Long prevBackupId = parentSnapshotOnBackupStore.getParentSnapshotId();
 
                 if (prevBackupId == 0) {
@@ -125,9 +123,15 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
                 }
 
                 parentSnapshotOnBackupStore = snapshotStoreDao.findBySnapshot(prevBackupId, DataStoreRole.Image);
+                if (parentSnapshotOnBackupStore == null) {
+                    break;
+                }
             }
+
             if (i >= deltaSnap) {
                 fullBackup = true;
+            } else {
+                fullBackup = false;
             }
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
index 6155ae9..dd3bee1 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
@@ -27,6 +27,7 @@ import java.util.List;
 
 import javax.inject.Inject;
 
+import com.cloud.utils.db.Transaction;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -59,6 +60,7 @@ public class DefaultEndPointSelector implements EndPointSelector {
     HostDao hostDao;
     private final String findOneHostOnPrimaryStorage = "select h.id from host h, storage_pool_host_ref s  where h.status = 'Up' and h.type = 'Routing' and h.resource_state = 'Enabled' and" +
             " h.id = s.host_id and s.pool_id = ? ";
+    private String findOneHypervisorHostInScope = "select h.id from host h where h.status = 'Up' and h.hypervisor_type is not null ";
 
     protected boolean moveBetweenPrimaryImage(DataStore srcStore, DataStore destStore) {
         DataStoreRole srcRole = srcStore.getRole();
@@ -292,4 +294,51 @@ public class DefaultEndPointSelector implements EndPointSelector {
         }
         return endPoints;
     }
+
+    @Override
+    public EndPoint selectHypervisorHost(Scope scope) {
+        StringBuilder sbuilder = new StringBuilder();
+        sbuilder.append(findOneHypervisorHostInScope);
+        if (scope.getScopeType() == ScopeType.ZONE) {
+            sbuilder.append(" and h.data_center_id = ");
+            sbuilder.append(scope.getScopeId());
+        } else if (scope.getScopeType() == ScopeType.CLUSTER) {
+            sbuilder.append(" and h.cluster_id = ");
+            sbuilder.append(scope.getScopeId());
+        }
+        sbuilder.append(" ORDER by rand() limit 1");
+
+        String sql = sbuilder.toString();
+        PreparedStatement pstmt = null;
+        ResultSet rs = null;
+        HostVO host = null;
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+
+        try {
+            pstmt = txn.prepareStatement(sql);
+            rs = pstmt.executeQuery();
+            while (rs.next()) {
+                long id = rs.getLong(1);
+                host = hostDao.findById(id);
+            }
+        } catch (SQLException e) {
+            s_logger.warn("can't find endpoint", e);
+        } finally {
+            try {
+                if (rs != null) {
+                    rs.close();
+                }
+                if (pstmt != null) {
+                    pstmt.close();
+                }
+            } catch (SQLException e) {
+            }
+        }
+
+        if (host == null) {
+            return null;
+        }
+
+        return RemoteHostEndPoint.getHypervisorHostEndPoint(host);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
index 7b9cf95..dc85fd8 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/image/db/SnapshotDataStoreDaoImpl.java
@@ -58,7 +58,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
             " and store_role = ? and volume_id = ? and state = 'Ready'" +
             " order by created DESC " +
             " limit 1";
-
+    private final String findLatestSnapshot = "select store_id, store_role, snapshot_id from cloud.snapshot_store_ref where " +
+            " store_role = ? and volume_id = ? and state = 'Ready'" +
+            " order by created DESC " +
+            " limit 1";
 
 
     @Override
@@ -190,6 +193,33 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
     }
 
     @Override
+    public SnapshotDataStoreVO findLatestSnapshotForVolume(Long volumeId, DataStoreRole role) {
+        TransactionLegacy txn = TransactionLegacy.currentTxn();
+        PreparedStatement pstmt = null;
+        ResultSet rs = null;
+        try {
+            pstmt = txn.prepareStatement(findLatestSnapshot);
+            pstmt.setString(1, role.toString());
+            pstmt.setLong(2, volumeId);
+            rs = pstmt.executeQuery();
+            while (rs.next()) {
+                long sid = rs.getLong(1);
+                long snid = rs.getLong(3);
+                return findByStoreSnapshot(role, sid, snid);
+            }
+        } catch (SQLException e) {
+            s_logger.debug("Failed to find parent snapshot: " + e.toString());
+        } finally {
+            try {
+                if (pstmt != null)
+                    pstmt.close();
+            } catch (SQLException e) {
+            }
+        }
+        return null;
+    }
+
+    @Override
     @DB
     public SnapshotDataStoreVO findParent(DataStoreRole role, Long storeId, Long volumeId) {
         TransactionLegacy txn = TransactionLegacy.currentTxn();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java
index 6dd6f3f..5ddde14 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/XenServerGuru.java
@@ -19,16 +19,29 @@ package com.cloud.hypervisor;
 import javax.ejb.Local;
 import javax.inject.Inject;
 
-import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.*;
+import com.cloud.host.HostInfo;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.GuestOSVO;
 import com.cloud.storage.dao.GuestOSDao;
 import com.cloud.template.VirtualMachineTemplate.BootloaderType;
+import com.cloud.utils.Pair;
 import com.cloud.vm.VirtualMachineProfile;
+import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
+import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
+import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
+import org.apache.cloudstack.storage.command.CopyCommand;
 
 @Local(value=HypervisorGuru.class)
 public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru {
     @Inject GuestOSDao _guestOsDao;
+    @Inject
+    EndPointSelector endPointSelector;
+    @Inject
+    HostDao hostDao;
 
     protected XenServerGuru() {
         super();
@@ -59,4 +72,29 @@ public class XenServerGuru extends HypervisorGuruBase implements HypervisorGuru
     public boolean trackVmHostChange() {
         return true;
     }
+
+    @Override
+    public Pair<Boolean, Long> getCommandHostDelegation(long hostId, Command cmd) {
+        if (cmd instanceof CopyCommand) {
+            CopyCommand cpyCommand = (CopyCommand)cmd;
+            DataTO srcData = cpyCommand.getSrcTO();
+            DataTO destData = cpyCommand.getDestTO();
+
+            if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) {
+                DataStoreTO srcStore = srcData.getDataStore();
+                DataStoreTO destStore = destData.getDataStore();
+                if (srcStore instanceof NfsTO && destStore instanceof NfsTO) {
+                    HostVO host = hostDao.findById(hostId);
+                    EndPoint ep = endPointSelector.selectHypervisorHost(new ZoneScope(host.getDataCenterId()));
+                    host = hostDao.findById(ep.getId());
+                    hostDao.loadDetails(host);
+                    boolean snapshotHotFix = Boolean.parseBoolean(host.getDetail(HostInfo.XS620_SNAPSHOT_HOTFIX));
+                    if (snapshotHotFix) {
+                        return new Pair<Boolean, Long>(Boolean.TRUE, new Long(ep.getId()));
+                    }
+                }
+            }
+        }
+        return new Pair<Boolean, Long>(Boolean.FALSE, new Long(hostId));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/15403a1f/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java
index 7174942..de4646f 100755
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java
@@ -34,13 +34,6 @@ import javax.persistence.EntityExistsException;
 import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
-import com.xensource.xenapi.Connection;
-import com.xensource.xenapi.Host;
-import com.xensource.xenapi.Pool;
-import com.xensource.xenapi.Session;
-import com.xensource.xenapi.Types.SessionAuthenticationFailed;
-import com.xensource.xenapi.Types.XenAPIException;
-
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.Listener;
 import com.cloud.agent.api.AgentControlAnswer;
@@ -82,6 +75,7 @@ import com.cloud.hypervisor.xen.resource.XenServer602Resource;
 import com.cloud.hypervisor.xen.resource.XenServer610Resource;
 import com.cloud.hypervisor.xen.resource.XenServer620Resource;
 import com.cloud.hypervisor.xen.resource.XenServerConnectionPool;
+import com.cloud.hypervisor.xen.resource.Xenserver625Resource;
 import com.cloud.resource.Discoverer;
 import com.cloud.resource.DiscovererBase;
 import com.cloud.resource.ResourceManager;
@@ -98,6 +92,12 @@ import com.cloud.utils.db.QueryBuilder;
 import com.cloud.utils.db.SearchCriteria.Op;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.exception.HypervisorVersionChangedException;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.Pool;
+import com.xensource.xenapi.Session;
+import com.xensource.xenapi.Types.SessionAuthenticationFailed;
+import com.xensource.xenapi.Types.XenAPIException;
 
 @Local(value=Discoverer.class)
 public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, Listener, ResourceStateAdapter {
@@ -112,6 +112,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
     protected String _guestNic;
     protected boolean _setupMultipath;
     protected String _instance;
+    private String xs620snapshothotfix = "Xenserver-Vdi-Copy-HotFix";
 
     @Inject protected AlertManager _alertMgr;
     @Inject protected AgentManager _agentMgr;
@@ -143,6 +144,11 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
         }
     }
 
+    protected boolean xenserverHotFixEnabled() {
+        //temporary fix, we should call xenserver api to get the hot fix is enabled or not.
+        return Boolean.parseBoolean(_configDao.getValue(Config.XenServerHotFix.name()));
+    }
+
     @Override
     public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url, String username, String password, List<String> hostTags) throws DiscoveryException {
         Map<CitrixResourceBase, Map<String, String>> resources = new HashMap<CitrixResourceBase, Map<String, String>>();
@@ -268,6 +274,8 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
                 	hostOS = record.softwareVersion.get("platform_name");
                 }
 
+                //Boolean xs620hotfix = record.tags.contains(xs620snapshothotfix);
+                Boolean xs620hotfix = xenserverHotFixEnabled();
                 String hostOSVer = prodVersion;
                 String hostKernelVer = record.softwareVersion.get("linux");
 
@@ -297,6 +305,7 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
                 details.put(HostInfo.HOST_OS_VERSION, hostOSVer);
                 details.put(HostInfo.HOST_OS_KERNEL_VERSION, hostKernelVer);
                 details.put(HostInfo.HYPERVISOR_VERSION, xenVersion);
+                details.put(HostInfo.XS620_SNAPSHOT_HOTFIX, xs620hotfix.toString());
 
                 String privateNetworkLabel = _networkMgr.getDefaultManagementTrafficLabel(dcId, HypervisorType.XenServer);
                 String storageNetworkLabel = _networkMgr.getDefaultStorageTrafficLabel(dcId, HypervisorType.XenServer);
@@ -451,9 +460,21 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
             return new XenServer602Resource();
         else if (prodBrand.equals("XenServer") && prodVersion.equals("6.1.0"))
             return new XenServer610Resource();
-        else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0"))
-            return new XenServer620Resource();
-        else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) {
+        else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0")) {
+            /*
+            Set<String> tags =record.tags;
+            if (tags.contains(xs620snapshothotfix)) {
+                return new Xenserver625Resource();
+            } else {
+                return new XenServer620Resource();
+            }*/
+            boolean hotfix = xenserverHotFixEnabled();
+            if (hotfix) {
+                return new Xenserver625Resource();
+            } else {
+                return new XenServer620Resource();
+            }
+        } else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) {
             String prodVersionTextShort = record.softwareVersion.get("product_version_text_short").trim();
             if ("5.6 SP2".equals(prodVersionTextShort)) {
                 return new XenServer56SP2Resource();
@@ -604,7 +625,12 @@ public class XcpServerDiscoverer extends DiscovererBase implements Discoverer, L
         } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.1.0")) {
             resource = XenServer610Resource.class.getName();
         } else if (prodBrand.equals("XenServer") && prodVersion.equals("6.2.0")) {
-            resource = XenServer620Resource.class.getName();
+            String hotfix = details.get("Xenserer620HotFix");
+            if (hotfix != null && hotfix.equalsIgnoreCase("Xenserver-Vdi-Copy-HotFix")) {
+                resource = Xenserver625Resource.class.getName();
+            } else {
+                resource = XenServer620Resource.class.getName();
+            }
         } else if (prodBrand.equals("XenServer") && prodVersion.equals("5.6.100")) {
             String prodVersionTextShort = details.get("product_version_text_short").trim();
             if ("5.6 SP2".equals(prodVersionTextShort)) {