This is an automated email from the ASF dual-hosted git repository.

weizhouapache pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 333973ab3cd Add xenserver.create.full.clone global setting (#13114)
333973ab3cd is described below

commit 333973ab3cd1a692dc34d536776c8cc21ebc75e1
Author: N/A <[email protected]>
AuthorDate: Wed Jul 8 17:17:34 2026 +0300

    Add xenserver.create.full.clone global setting (#13114)
    
    * Add xenserver.create.full.clone global setting
    
    Adds a StoragePool-scoped boolean ConfigKey mirroring 
vmware.create.full.clone
    so XenServer-backed VMs can be deployed as full VDI copies (VDI.copy) 
instead
    of always using linked clones (VDI.clone). Default false preserves today's
    behavior.
    
    The per-pool flag flows into the existing PrimaryDataStoreTO.fullCloneFlag
    through a new dispatch method 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest
    that switches on hypervisor type.
    
    * Fix HypervisorType dispatch in addFullClone flag helper
    
    Replace invalid switch on Hypervisor.HypervisorType (not a Java enum) with
    equality checks so cloud-engine-storage-datamotion compiles.
    
    ---------
    
    Co-authored-by: Erki Märks <[email protected]>
---
 .../java/com/cloud/storage/StorageManager.java     |  8 ++++
 .../storage/motion/AncientDataMotionStrategy.java  | 51 +++++++++++++++++++---
 .../motion/AncientDataMotionStrategyTest.java      |  8 ++++
 .../resource/XenServerStorageProcessor.java        |  9 +++-
 .../java/com/cloud/storage/StorageManagerImpl.java |  1 +
 5 files changed, 69 insertions(+), 8 deletions(-)

diff --git 
a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java 
b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index 3c62738f9ed..d6604cffc40 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -195,6 +195,14 @@ public interface StorageManager extends StorageService {
             true,
             ConfigKey.Scope.StoragePool,
             null);
+    ConfigKey<Boolean> XenserverCreateCloneFull = new 
ConfigKey<>(Boolean.class,
+            "xenserver.create.full.clone",
+            "Storage",
+            "false",
+            "If set to true, creates VMs as full clones on XenServer 
hypervisor (uses VDI.copy instead of VDI.clone, removing the linked-clone 
parent relationship).",
+            true,
+            ConfigKey.Scope.StoragePool,
+            null);
     ConfigKey<Boolean> VmwareAllowParallelExecution = new 
ConfigKey<>(Boolean.class,
             "vmware.allow.parallel.command.execution",
             "Advanced",
diff --git 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 1144a29986a..dd54dd58005 100644
--- 
a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ 
b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -191,7 +191,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
                 srcForCopy = cacheData = cacheMgr.createCacheObject(srcData, 
destScope);
             }
 
-            CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), 
primaryStorageDownloadWait,
+            CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), 
primaryStorageDownloadWait,
                     VirtualMachineManager.ExecuteInSequence.value());
             EndPoint ep = destHost != null ? 
RemoteHostEndPoint.getHypervisorHostEndPoint(destHost) : 
selector.select(srcForCopy, destData);
             if (ep == null) {
@@ -257,6 +257,43 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
         return dataTO;
     }
 
+    /**
+     * Adds {@code 'xenserver.create.full.clone'} value for a given primary 
storage, whose HV is XenServer, on datastore's {@code fullCloneFlag} field
+     * @param dataTO Dest data store TO
+     * @return dataTO including fullCloneFlag, if provided
+     */
+    protected DataTO 
addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(DataTO dataTO) {
+        if (dataTO != null && 
dataTO.getHypervisorType().equals(Hypervisor.HypervisorType.XenServer)){
+            DataStoreTO dataStoreTO = dataTO.getDataStore();
+            if (dataStoreTO != null && dataStoreTO instanceof 
PrimaryDataStoreTO){
+                PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) 
dataStoreTO;
+                
primaryDataStoreTO.setFullCloneFlag(StorageManager.XenserverCreateCloneFull.valueIn(primaryDataStoreTO.getId()));
+            }
+        }
+        return dataTO;
+    }
+
+    /**
+     * Dispatches to the per-hypervisor {@code 
addFullCloneAndDiskprovisiongStrictnessFlagOn*Dest} helper
+     * based on {@code dataTO.getHypervisorType()}. Returns {@code dataTO} 
unchanged for hypervisors
+     * that do not have a full-clone toggle.
+     * @param dataTO Dest data store TO
+     * @return dataTO including fullCloneFlag, if provided
+     */
+    protected DataTO addFullCloneAndDiskprovisiongStrictnessFlagOnDest(DataTO 
dataTO) {
+        if (dataTO == null) {
+            return dataTO;
+        }
+        Hypervisor.HypervisorType hypervisorType = dataTO.getHypervisorType();
+        if (Hypervisor.HypervisorType.VMware.equals(hypervisorType)) {
+            return 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(dataTO);
+        }
+        if (Hypervisor.HypervisorType.XenServer.equals(hypervisorType)) {
+            return 
addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(dataTO);
+        }
+        return dataTO;
+    }
+
     protected Answer copyObject(DataObject srcData, DataObject destData) {
         return copyObject(srcData, destData, null);
     }
@@ -315,7 +352,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
 
             updateLockHostForVolume(ep, volObj);
 
-            CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(volObj.getTO()), 
_createVolumeFromSnapshotWait, VirtualMachineManager.ExecuteInSequence.value());
+            CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(volObj.getTO()), 
_createVolumeFromSnapshotWait, VirtualMachineManager.ExecuteInSequence.value());
 
             Answer answer = null;
             if (ep == null) {
@@ -361,7 +398,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
     }
 
     protected Answer cloneVolume(DataObject template, DataObject volume) {
-        CopyCommand cmd = new CopyCommand(template.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(volume.getTO()), 0, 
VirtualMachineManager.ExecuteInSequence.value());
+        CopyCommand cmd = new CopyCommand(template.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(volume.getTO()), 0, 
VirtualMachineManager.ExecuteInSequence.value());
         try {
             EndPoint ep = selector.select(volume, 
anyVolumeRequiresEncryption(volume));
             Answer answer = null;
@@ -445,7 +482,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
 
                 objOnImageStore.processEvent(Event.CopyingRequested);
 
-                CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), 
_copyvolumewait, VirtualMachineManager.ExecuteInSequence.value());
+                CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), 
_copyvolumewait, VirtualMachineManager.ExecuteInSequence.value());
                 EndPoint ep = selector.select(objOnImageStore, destData, 
encryptionRequired);
                 if (ep == null) {
                     String errMsg = 
String.format(NO_REMOTE_ENDPOINT_WITH_ENCRYPTION, encryptionRequired);
@@ -692,7 +729,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
             ep = selector.select(srcData, destData);
         }
 
-        CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), 
_createprivatetemplatefromsnapshotwait, 
VirtualMachineManager.ExecuteInSequence.value());
+        CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), 
_createprivatetemplatefromsnapshotwait, 
VirtualMachineManager.ExecuteInSequence.value());
         Answer answer = null;
         if (ep == null) {
             logger.error(NO_REMOTE_ENDPOINT_SSVM);
@@ -730,7 +767,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
                 Scope selectedScope = pickCacheScopeForCopy(srcData, destData);
                 cacheData = cacheMgr.getCacheObject(srcData, selectedScope);
 
-                CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), 
_backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
+                CopyCommand cmd = new CopyCommand(srcData.getTO(), 
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), 
_backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
                 cmd.setCacheTO(cacheData.getTO());
                 cmd.setOptions(options);
                 EndPoint ep = selector.select(srcData, destData, 
encryptionRequired);
@@ -741,7 +778,7 @@ public class AncientDataMotionStrategy implements 
DataMotionStrategy {
                     answer = ep.sendMessage(cmd);
                 }
             } else {
-                
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO());
+                
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO());
                 CopyCommand cmd = new CopyCommand(srcData.getTO(), 
destData.getTO(), _backupsnapshotwait, 
VirtualMachineManager.ExecuteInSequence.value());
                 cmd.setOptions(options);
                 EndPoint ep = selector.select(srcData, destData, 
StorageAction.BACKUPSNAPSHOT, encryptionRequired);
diff --git 
a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategyTest.java
 
b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategyTest.java
index e84163656b1..86af81899e8 100755
--- 
a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategyTest.java
+++ 
b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategyTest.java
@@ -113,6 +113,14 @@ public class AncientDataMotionStrategyTest {
         verify(dataStoreTO).setFullCloneFlag(FULL_CLONE_FLAG);
     }
 
+    @Test
+    public void testAddFullCloneFlagOnXenServerDest() throws 
IllegalAccessException, NoSuchFieldException {
+        overrideDefaultConfigValue(StorageManager.XenserverCreateCloneFull, 
String.valueOf(FULL_CLONE_FLAG));
+        when(dataTO.getHypervisorType()).thenReturn(HypervisorType.XenServer);
+        
strategy.addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(dataTO);
+        verify(dataStoreTO).setFullCloneFlag(FULL_CLONE_FLAG);
+    }
+
     @Test
     public void testAddFullCloneFlagOnNotVmwareDest(){
         verify(dataStoreTO, never()).setFullCloneFlag(any(Boolean.class));
diff --git 
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
 
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
index c9e6118340c..a1d27b65aba 100644
--- 
a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
+++ 
b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java
@@ -859,12 +859,19 @@ public class XenServerStorageProcessor implements 
StorageProcessor {
         final DataTO srcData = cmd.getSrcTO();
         final DataTO destData = cmd.getDestTO();
         final VolumeObjectTO volume = (VolumeObjectTO) destData;
+        final DataStoreTO destStore = volume.getDataStore();
+        final boolean fullClone = destStore instanceof PrimaryDataStoreTO
+                && Boolean.TRUE.equals(((PrimaryDataStoreTO) 
destStore).isFullCloneFlag());
         VDI vdi = null;
         try {
             VDI tmpltvdi = null;
 
             tmpltvdi = getVDIbyUuid(conn, srcData.getPath());
-            vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
+            if (fullClone) {
+                vdi = tmpltvdi.copy(conn, tmpltvdi.getSR(conn));
+            } else {
+                vdi = tmpltvdi.createClone(conn, new HashMap<String, 
String>());
+            }
             Long virtualSize  = vdi.getVirtualSize(conn);
             if (volume.getSize() > virtualSize) {
                 logger.debug("Overriding provided Template's size with new 
size " + toHumanReadableSize(volume.getSize()) + " for volume: " + 
volume.getName());
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java 
b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index ae2facf3861..9cb5155753c 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -4621,6 +4621,7 @@ public class StorageManagerImpl extends ManagerBase 
implements StorageManager, C
                 SecStorageVMAutoScaleDown,
                 MountDisabledStoragePool,
                 VmwareCreateCloneFull,
+                XenserverCreateCloneFull,
                 VmwareAllowParallelExecution,
                 DataStoreDownloadFollowRedirects,
                 AllowVolumeReSizeBeyondAllocation,

Reply via email to