You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by we...@apache.org on 2026/07/08 14:18:09 UTC
(cloudstack) branch main updated: Add xenserver.create.full.clone global setting (#13114)
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 <16...@users.noreply.github.com>
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 <er...@users.noreply.github.com>
---
.../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,