From df0c0045b52e8c12854eb7ef72aae25f62a28ee1 Mon Sep 17 00:00:00 2001 From: Harikrishna Date: Thu, 30 Sep 2021 21:14:02 +0530 Subject: [PATCH] Fix export snapshot and template to secondary storage to export only required disk (#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 --- .../resource/VmwareStorageProcessor.java | 18 +++-- .../vmware/mo/VirtualMachineMO.java | 72 +++++++++++++++---- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java index 7ed4e2f4f1be..b3ab3fe83897 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -1241,10 +1241,11 @@ private Ternary 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 @@ -1828,14 +1829,11 @@ private Pair 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); diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 238493557c33..c27470e3ad66 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -751,43 +751,87 @@ public boolean hasSnapshot() throws Exception { return false; } - public boolean createFullCloneWithSpecificDisk(String cloneName, ManagedObjectReference morFolder, ManagedObjectReference morResourcePool, ManagedObjectReference morDs, Pair 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 diskLocator = new ArrayList(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 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)