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,