Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix export snapshot and template to secondary storage to export only required disk #5510

Merged
merged 5 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1241,10 +1241,11 @@ private Ternary<String, Long, Long> createTemplateFromVolume(VmwareContext conte

DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
vmMo.createFullCloneWithSpecificDisk(templateUniqueName, dcMo.getVmFolder(), morPool, VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()), volumeDeviceInfo);
clonedVm = dcMo.findVm(templateUniqueName);

clonedVm.tagAsWorkerVM();
VirtualDisk requiredDisk = volumeDeviceInfo.first();
clonedVm = vmMo.createFullCloneWithSpecificDisk(templateUniqueName, dcMo.getVmFolder(), morPool, requiredDisk);
if (clonedVm == null) {
throw new Exception(String.format("Failed to clone VM with name %s during create template from volume operation", templateUniqueName));
}
clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, false, false);

// Get VMDK filename
Expand Down Expand Up @@ -1828,14 +1829,11 @@ private Pair<String, String[]> exportVolumeToSecondaryStorage(VmwareContext cont
// 4 MB is the minimum requirement for VM memory in VMware
DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
vmMo.createFullCloneWithSpecificDisk(exportName, dcMo.getVmFolder(), morPool, VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()), volumeDeviceInfo);
clonedVm = dcMo.findVm(exportName);
VirtualDisk requiredDisk = volumeDeviceInfo.first();
clonedVm = vmMo.createFullCloneWithSpecificDisk(exportName, dcMo.getVmFolder(), morPool, requiredDisk);
if (clonedVm == null) {
String msg = "Failed to clone VM. volume path: " + volumePath;
s_logger.error(msg);
throw new Exception(msg);
throw new Exception(String.format("Failed to clone VM with name %s during export volume operation", exportName));
}
clonedVm.tagAsWorkerVM();
vmMo = clonedVm;
}
vmMo.exportVm(exportPath, exportName, false, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -751,43 +751,87 @@ public boolean hasSnapshot() throws Exception {
return false;
}

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

assert (morFolder != null);
assert (morResourcePool != null);
assert (morDs != null);
VirtualDisk requiredDisk = volumeDeviceInfo.first();
VirtualMachineRuntimeInfo runtimeInfo = getRuntimeInfo();
HostMO hostMo = new HostMO(_context, runtimeInfo.getHost());
DatacenterMO dcMo = new DatacenterMO(_context, hostMo.getHyperHostDatacenter());
DatastoreMO dsMo = new DatastoreMO(_context, morResourcePool);

VirtualMachineRelocateSpec rSpec = new VirtualMachineRelocateSpec();
List<VirtualMachineRelocateSpecDiskLocator> diskLocator = new ArrayList<VirtualMachineRelocateSpecDiskLocator>(1);
VirtualMachineRelocateSpecDiskLocator loc = new VirtualMachineRelocateSpecDiskLocator();
loc.setDatastore(morDs);
loc.setDiskId(requiredDisk.getKey());
loc.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.MOVE_ALL_DISK_BACKINGS_AND_DISALLOW_SHARING.value());
diskLocator.add(loc);

rSpec.setDiskMoveType(VirtualMachineRelocateDiskMoveOptions.MOVE_ALL_DISK_BACKINGS_AND_DISALLOW_SHARING.value());
rSpec.getDisk().addAll(diskLocator);

VirtualDisk[] vmDisks = getAllDiskDevice();
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
s_logger.debug(String.format("Removing the disks other than the required disk with key %s to the cloned VM", requiredDisk.getKey()));
for (VirtualDisk disk : vmDisks) {
s_logger.debug(String.format("Original disk with key %s found in the VM %s", disk.getKey(), getName()));
if (requiredDisk.getKey() != disk.getKey()) {
VirtualDeviceConfigSpec virtualDeviceConfigSpec = new VirtualDeviceConfigSpec();
virtualDeviceConfigSpec.setDevice(disk);
virtualDeviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.REMOVE);
vmConfigSpec.getDeviceChange().add(virtualDeviceConfigSpec);
}
}
rSpec.setPool(morResourcePool);

VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
cloneSpec.setPowerOn(false);
cloneSpec.setTemplate(false);
cloneSpec.setLocation(rSpec);
cloneSpec.setMemory(false);
cloneSpec.setConfig(vmConfigSpec);

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

boolean result = _context.getVimClient().waitForTask(morTask);
if (result) {
_context.waitForTaskProgressDone(morTask);
VirtualMachineMO clonedVm = dcMo.findVm(cloneName);
if (clonedVm == null) {
s_logger.error(String.format("Failed to clone VM %s", cloneName));
return null;
}
s_logger.debug(String.format("Cloned VM: %s as %s", getName(), cloneName));
return true;
clonedVm.tagAsWorkerVM();
makeSureVMHasOnlyRequiredDisk(clonedVm, requiredDisk, dsMo, dcMo);
return clonedVm;
} else {
s_logger.error("VMware cloneVM_Task failed due to " + TaskMO.getTaskFailureInfo(_context, morTask));
return null;
}
}

return false;
private void makeSureVMHasOnlyRequiredDisk(VirtualMachineMO clonedVm, VirtualDisk requiredDisk, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception {

String vmName = clonedVm.getName();
VirtualDisk[] vmDisks = clonedVm.getAllDiskDevice();
s_logger.debug(String.format("Checking if VM %s is created only with required Disk, if not detach the remaining disks", vmName));
if (vmDisks.length == 1) {
s_logger.debug(String.format("VM %s is created only with required Disk", vmName));
return;
}

VirtualDisk requiredCloneDisk = null;
for (VirtualDisk vmDisk: vmDisks) {
if (vmDisk.getKey() == requiredDisk.getKey()) {
requiredCloneDisk = vmDisk;
break;
}
}
if (requiredCloneDisk == null) {
s_logger.error(String.format("Failed to identify required disk in VM %s", vmName));
throw new CloudRuntimeException(String.format("VM %s is not created with required disk", vmName));
}

String baseName = VmwareHelper.getDiskDeviceFileName(requiredCloneDisk);
s_logger.debug(String.format("Detaching all disks for the VM: %s except disk with base name: %s, key=%d", vmName, baseName, requiredCloneDisk.getKey()));
List<String> detachedDisks = clonedVm.detachAllDisksExcept(baseName, null);
for (String diskPath : detachedDisks) {
dsMo.deleteFile(diskPath, dcMo.getMor(), true, null);
}
}

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