Skip to content

Commit df0c004

Browse files
Fix export snapshot and template to secondary storage to export only required disk (apache#5510)
* Fix export snapshot and export template to secondary storage in VMware to export only one required disk * Move clone operation into virtual machine mo * Code refactored for readability * Added disk key check even for successful clone operation * Delete dettached disks from cloned VM and added few logs
1 parent 32051fb commit df0c004

File tree

2 files changed

+66
-24
lines changed

2 files changed

+66
-24
lines changed

plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,10 +1241,11 @@ private Ternary<String, Long, Long> createTemplateFromVolume(VmwareContext conte
12411241

12421242
DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
12431243
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
1244-
vmMo.createFullCloneWithSpecificDisk(templateUniqueName, dcMo.getVmFolder(), morPool, VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()), volumeDeviceInfo);
1245-
clonedVm = dcMo.findVm(templateUniqueName);
1246-
1247-
clonedVm.tagAsWorkerVM();
1244+
VirtualDisk requiredDisk = volumeDeviceInfo.first();
1245+
clonedVm = vmMo.createFullCloneWithSpecificDisk(templateUniqueName, dcMo.getVmFolder(), morPool, requiredDisk);
1246+
if (clonedVm == null) {
1247+
throw new Exception(String.format("Failed to clone VM with name %s during create template from volume operation", templateUniqueName));
1248+
}
12481249
clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, false, false);
12491250

12501251
// Get VMDK filename
@@ -1828,14 +1829,11 @@ private Pair<String, String[]> exportVolumeToSecondaryStorage(VmwareContext cont
18281829
// 4 MB is the minimum requirement for VM memory in VMware
18291830
DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
18301831
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
1831-
vmMo.createFullCloneWithSpecificDisk(exportName, dcMo.getVmFolder(), morPool, VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()), volumeDeviceInfo);
1832-
clonedVm = dcMo.findVm(exportName);
1832+
VirtualDisk requiredDisk = volumeDeviceInfo.first();
1833+
clonedVm = vmMo.createFullCloneWithSpecificDisk(exportName, dcMo.getVmFolder(), morPool, requiredDisk);
18331834
if (clonedVm == null) {
1834-
String msg = "Failed to clone VM. volume path: " + volumePath;
1835-
s_logger.error(msg);
1836-
throw new Exception(msg);
1835+
throw new Exception(String.format("Failed to clone VM with name %s during export volume operation", exportName));
18371836
}
1838-
clonedVm.tagAsWorkerVM();
18391837
vmMo = clonedVm;
18401838
}
18411839
vmMo.exportVm(exportPath, exportName, false, false);

vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -751,43 +751,87 @@ public boolean hasSnapshot() throws Exception {
751751
return false;
752752
}
753753

754-
public boolean createFullCloneWithSpecificDisk(String cloneName, ManagedObjectReference morFolder, ManagedObjectReference morResourcePool, ManagedObjectReference morDs, Pair<VirtualDisk, String> volumeDeviceInfo)
754+
public VirtualMachineMO createFullCloneWithSpecificDisk(String cloneName, ManagedObjectReference morFolder, ManagedObjectReference morResourcePool, VirtualDisk requiredDisk)
755755
throws Exception {
756756

757757
assert (morFolder != null);
758758
assert (morResourcePool != null);
759-
assert (morDs != null);
760-
VirtualDisk requiredDisk = volumeDeviceInfo.first();
759+
VirtualMachineRuntimeInfo runtimeInfo = getRuntimeInfo();
760+
HostMO hostMo = new HostMO(_context, runtimeInfo.getHost());
761+
DatacenterMO dcMo = new DatacenterMO(_context, hostMo.getHyperHostDatacenter());
762+
DatastoreMO dsMo = new DatastoreMO(_context, morResourcePool);
761763

762764
VirtualMachineRelocateSpec rSpec = new VirtualMachineRelocateSpec();
763-
List<VirtualMachineRelocateSpecDiskLocator> diskLocator = new ArrayList<VirtualMachineRelocateSpecDiskLocator>(1);
764-
VirtualMachineRelocateSpecDiskLocator loc = new VirtualMachineRelocateSpecDiskLocator();
765-
loc.setDatastore(morDs);
766-
loc.setDiskId(requiredDisk.getKey());
767-
loc.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.MOVE_ALL_DISK_BACKINGS_AND_DISALLOW_SHARING.value());
768-
diskLocator.add(loc);
769-
770-
rSpec.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.MOVE_ALL_DISK_BACKINGS_AND_DISALLOW_SHARING.value());
771-
rSpec.getDisk().addAll(diskLocator);
765+
766+
VirtualDisk[] vmDisks = getAllDiskDevice();
767+
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
768+
s_logger.debug(String.format("Removing the disks other than the required disk with key %s to the cloned VM", requiredDisk.getKey()));
769+
for (VirtualDisk disk : vmDisks) {
770+
s_logger.debug(String.format("Original disk with key %s found in the VM %s", disk.getKey(), getName()));
771+
if (requiredDisk.getKey() != disk.getKey()) {
772+
VirtualDeviceConfigSpec virtualDeviceConfigSpec = new VirtualDeviceConfigSpec();
773+
virtualDeviceConfigSpec.setDevice(disk);
774+
virtualDeviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.REMOVE);
775+
vmConfigSpec.getDeviceChange().add(virtualDeviceConfigSpec);
776+
}
777+
}
772778
rSpec.setPool(morResourcePool);
773779

774780
VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
775781
cloneSpec.setPowerOn(false);
776782
cloneSpec.setTemplate(false);
777783
cloneSpec.setLocation(rSpec);
784+
cloneSpec.setMemory(false);
785+
cloneSpec.setConfig(vmConfigSpec);
778786

779787
ManagedObjectReference morTask = _context.getService().cloneVMTask(_mor, morFolder, cloneName, cloneSpec);
780788

781789
boolean result = _context.getVimClient().waitForTask(morTask);
782790
if (result) {
783791
_context.waitForTaskProgressDone(morTask);
792+
VirtualMachineMO clonedVm = dcMo.findVm(cloneName);
793+
if (clonedVm == null) {
794+
s_logger.error(String.format("Failed to clone VM %s", cloneName));
795+
return null;
796+
}
784797
s_logger.debug(String.format("Cloned VM: %s as %s", getName(), cloneName));
785-
return true;
798+
clonedVm.tagAsWorkerVM();
799+
makeSureVMHasOnlyRequiredDisk(clonedVm, requiredDisk, dsMo, dcMo);
800+
return clonedVm;
786801
} else {
787802
s_logger.error("VMware cloneVM_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
803+
return null;
788804
}
805+
}
789806

790-
return false;
807+
private void makeSureVMHasOnlyRequiredDisk(VirtualMachineMO clonedVm, VirtualDisk requiredDisk, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception {
808+
809+
String vmName = clonedVm.getName();
810+
VirtualDisk[] vmDisks = clonedVm.getAllDiskDevice();
811+
s_logger.debug(String.format("Checking if VM %s is created only with required Disk, if not detach the remaining disks", vmName));
812+
if (vmDisks.length == 1) {
813+
s_logger.debug(String.format("VM %s is created only with required Disk", vmName));
814+
return;
815+
}
816+
817+
VirtualDisk requiredCloneDisk = null;
818+
for (VirtualDisk vmDisk: vmDisks) {
819+
if (vmDisk.getKey() == requiredDisk.getKey()) {
820+
requiredCloneDisk = vmDisk;
821+
break;
822+
}
823+
}
824+
if (requiredCloneDisk == null) {
825+
s_logger.error(String.format("Failed to identify required disk in VM %s", vmName));
826+
throw new CloudRuntimeException(String.format("VM %s is not created with required disk", vmName));
827+
}
828+
829+
String baseName = VmwareHelper.getDiskDeviceFileName(requiredCloneDisk);
830+
s_logger.debug(String.format("Detaching all disks for the VM: %s except disk with base name: %s, key=%d", vmName, baseName, requiredCloneDisk.getKey()));
831+
List<String> detachedDisks = clonedVm.detachAllDisksExcept(baseName, null);
832+
for (String diskPath : detachedDisks) {
833+
dsMo.deleteFile(diskPath, dcMo.getMor(), true, null);
834+
}
791835
}
792836

793837
public boolean createFullClone(String cloneName, ManagedObjectReference morFolder, ManagedObjectReference morResourcePool, ManagedObjectReference morDs, Storage.ProvisioningType diskProvisioningType)

0 commit comments

Comments
 (0)