Skip to content

Commit 6cd5a55

Browse files
committed
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.
1 parent 5893ba5 commit 6cd5a55

5 files changed

Lines changed: 69 additions & 8 deletions

File tree

engine/components-api/src/main/java/com/cloud/storage/StorageManager.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,14 @@ public interface StorageManager extends StorageService {
195195
true,
196196
ConfigKey.Scope.StoragePool,
197197
null);
198+
ConfigKey<Boolean> XenserverCreateCloneFull = new ConfigKey<>(Boolean.class,
199+
"xenserver.create.full.clone",
200+
"Storage",
201+
"false",
202+
"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).",
203+
true,
204+
ConfigKey.Scope.StoragePool,
205+
null);
198206
ConfigKey<Boolean> VmwareAllowParallelExecution = new ConfigKey<>(Boolean.class,
199207
"vmware.allow.parallel.command.execution",
200208
"Advanced",

engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ protected Answer copyObject(DataObject srcData, DataObject destData, Host destHo
187187
srcForCopy = cacheData = cacheMgr.createCacheObject(srcData, destScope);
188188
}
189189

190-
CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), primaryStorageDownloadWait,
190+
CopyCommand cmd = new CopyCommand(srcForCopy.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), primaryStorageDownloadWait,
191191
VirtualMachineManager.ExecuteInSequence.value());
192192
EndPoint ep = destHost != null ? RemoteHostEndPoint.getHypervisorHostEndPoint(destHost) : selector.select(srcForCopy, destData);
193193
if (ep == null) {
@@ -253,6 +253,43 @@ protected DataTO addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(DataTO
253253
return dataTO;
254254
}
255255

256+
/**
257+
* Adds {@code 'xenserver.create.full.clone'} value for a given primary storage, whose HV is XenServer, on datastore's {@code fullCloneFlag} field
258+
* @param dataTO Dest data store TO
259+
* @return dataTO including fullCloneFlag, if provided
260+
*/
261+
protected DataTO addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(DataTO dataTO) {
262+
if (dataTO != null && dataTO.getHypervisorType().equals(Hypervisor.HypervisorType.XenServer)){
263+
DataStoreTO dataStoreTO = dataTO.getDataStore();
264+
if (dataStoreTO != null && dataStoreTO instanceof PrimaryDataStoreTO){
265+
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) dataStoreTO;
266+
primaryDataStoreTO.setFullCloneFlag(StorageManager.XenserverCreateCloneFull.valueIn(primaryDataStoreTO.getId()));
267+
}
268+
}
269+
return dataTO;
270+
}
271+
272+
/**
273+
* Dispatches to the per-hypervisor {@code addFullCloneAndDiskprovisiongStrictnessFlagOn*Dest} helper
274+
* based on {@code dataTO.getHypervisorType()}. Returns {@code dataTO} unchanged for hypervisors
275+
* that do not have a full-clone toggle.
276+
* @param dataTO Dest data store TO
277+
* @return dataTO including fullCloneFlag, if provided
278+
*/
279+
protected DataTO addFullCloneAndDiskprovisiongStrictnessFlagOnDest(DataTO dataTO) {
280+
if (dataTO == null) {
281+
return dataTO;
282+
}
283+
switch (dataTO.getHypervisorType()) {
284+
case VMware:
285+
return addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(dataTO);
286+
case XenServer:
287+
return addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(dataTO);
288+
default:
289+
return dataTO;
290+
}
291+
}
292+
256293
protected Answer copyObject(DataObject srcData, DataObject destData) {
257294
return copyObject(srcData, destData, null);
258295
}
@@ -309,7 +346,7 @@ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {
309346
ep = selector.select(srcData, volObj);
310347
}
311348

312-
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(volObj.getTO()), _createVolumeFromSnapshotWait, VirtualMachineManager.ExecuteInSequence.value());
349+
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(volObj.getTO()), _createVolumeFromSnapshotWait, VirtualMachineManager.ExecuteInSequence.value());
313350

314351
Answer answer = null;
315352
if (ep == null) {
@@ -332,7 +369,7 @@ protected Answer copyVolumeFromSnapshot(DataObject snapObj, DataObject volObj) {
332369
}
333370

334371
protected Answer cloneVolume(DataObject template, DataObject volume) {
335-
CopyCommand cmd = new CopyCommand(template.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(volume.getTO()), 0, VirtualMachineManager.ExecuteInSequence.value());
372+
CopyCommand cmd = new CopyCommand(template.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(volume.getTO()), 0, VirtualMachineManager.ExecuteInSequence.value());
336373
try {
337374
EndPoint ep = selector.select(volume, anyVolumeRequiresEncryption(volume));
338375
Answer answer = null;
@@ -416,7 +453,7 @@ protected Answer copyVolumeBetweenPools(DataObject srcData, DataObject destData)
416453

417454
objOnImageStore.processEvent(Event.CopyingRequested);
418455

419-
CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), _copyvolumewait, VirtualMachineManager.ExecuteInSequence.value());
456+
CopyCommand cmd = new CopyCommand(objOnImageStore.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), _copyvolumewait, VirtualMachineManager.ExecuteInSequence.value());
420457
EndPoint ep = selector.select(objOnImageStore, destData, encryptionRequired);
421458
if (ep == null) {
422459
String errMsg = String.format(NO_REMOTE_ENDPOINT_WITH_ENCRYPTION, encryptionRequired);
@@ -660,7 +697,7 @@ protected Answer createTemplateFromSnapshot(DataObject srcData, DataObject destD
660697
ep = selector.select(srcData, destData);
661698
}
662699

663-
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), _createprivatetemplatefromsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
700+
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), _createprivatetemplatefromsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
664701
Answer answer = null;
665702
if (ep == null) {
666703
logger.error(NO_REMOTE_ENDPOINT_SSVM);
@@ -698,7 +735,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
698735
Scope selectedScope = pickCacheScopeForCopy(srcData, destData);
699736
cacheData = cacheMgr.getCacheObject(srcData, selectedScope);
700737

701-
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO()), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
738+
CopyCommand cmd = new CopyCommand(srcData.getTO(), addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO()), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
702739
cmd.setCacheTO(cacheData.getTO());
703740
cmd.setOptions(options);
704741
EndPoint ep = selector.select(srcData, destData, encryptionRequired);
@@ -709,7 +746,7 @@ protected Answer copySnapshot(DataObject srcData, DataObject destData) {
709746
answer = ep.sendMessage(cmd);
710747
}
711748
} else {
712-
addFullCloneAndDiskprovisiongStrictnessFlagOnVMwareDest(destData.getTO());
749+
addFullCloneAndDiskprovisiongStrictnessFlagOnDest(destData.getTO());
713750
CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _backupsnapshotwait, VirtualMachineManager.ExecuteInSequence.value());
714751
cmd.setOptions(options);
715752
EndPoint ep = selector.select(srcData, destData, StorageAction.BACKUPSNAPSHOT, encryptionRequired);

engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/AncientDataMotionStrategyTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,14 @@ public void testAddFullCloneFlagOnVMwareDest(){
101101
verify(dataStoreTO).setFullCloneFlag(FULL_CLONE_FLAG);
102102
}
103103

104+
@Test
105+
public void testAddFullCloneFlagOnXenServerDest() throws IllegalAccessException, NoSuchFieldException {
106+
overrideDefaultConfigValue(StorageManager.XenserverCreateCloneFull, String.valueOf(FULL_CLONE_FLAG));
107+
when(dataTO.getHypervisorType()).thenReturn(HypervisorType.XenServer);
108+
strategy.addFullCloneAndDiskprovisiongStrictnessFlagOnXenServerDest(dataTO);
109+
verify(dataStoreTO).setFullCloneFlag(FULL_CLONE_FLAG);
110+
}
111+
104112
@Test
105113
public void testAddFullCloneFlagOnNotVmwareDest(){
106114
verify(dataStoreTO, never()).setFullCloneFlag(any(Boolean.class));

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServerStorageProcessor.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,12 +859,19 @@ public Answer cloneVolumeFromBaseTemplate(final CopyCommand cmd) {
859859
final DataTO srcData = cmd.getSrcTO();
860860
final DataTO destData = cmd.getDestTO();
861861
final VolumeObjectTO volume = (VolumeObjectTO) destData;
862+
final DataStoreTO destStore = volume.getDataStore();
863+
final boolean fullClone = destStore instanceof PrimaryDataStoreTO
864+
&& Boolean.TRUE.equals(((PrimaryDataStoreTO) destStore).isFullCloneFlag());
862865
VDI vdi = null;
863866
try {
864867
VDI tmpltvdi = null;
865868

866869
tmpltvdi = getVDIbyUuid(conn, srcData.getPath());
867-
vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
870+
if (fullClone) {
871+
vdi = tmpltvdi.copy(conn, tmpltvdi.getSR(conn));
872+
} else {
873+
vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
874+
}
868875
Long virtualSize = vdi.getVirtualSize(conn);
869876
if (volume.getSize() > virtualSize) {
870877
logger.debug("Overriding provided Template's size with new size " + toHumanReadableSize(volume.getSize()) + " for volume: " + volume.getName());

server/src/main/java/com/cloud/storage/StorageManagerImpl.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4616,6 +4616,7 @@ public ConfigKey<?>[] getConfigKeys() {
46164616
SecStorageVMAutoScaleDown,
46174617
MountDisabledStoragePool,
46184618
VmwareCreateCloneFull,
4619+
XenserverCreateCloneFull,
46194620
VmwareAllowParallelExecution,
46204621
DataStoreDownloadFollowRedirects,
46214622
AllowVolumeReSizeBeyondAllocation,

0 commit comments

Comments
 (0)