From a3c764445bb4e395cdacf80332dc3a0c7727efc0 Mon Sep 17 00:00:00 2001 From: Suresh Kumar Anaparti Date: Wed, 10 May 2017 02:17:12 +0530 Subject: [PATCH 1/4] CLOUDSTACK-8609 [VMware] VM is not accessible after migration across clusters --- .../vmware/resource/VmwareResource.java | 37 ++++++++++++++----- .../vmware/mo/VirtualMachineMO.java | 33 +++++++++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index cfd565f0f94c..c3eefc28bfde 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1528,6 +1528,7 @@ protected StartAnswer execute(StartCommand cmd) { String existingVmName = null; VirtualMachineFileInfo existingVmFileInfo = null; VirtualMachineFileLayoutEx existingVmFileLayout = null; + List existingDatastores = new ArrayList(); Pair names = composeVmNames(vmSpec); String vmInternalCSName = names.first(); @@ -1650,6 +1651,7 @@ protected StartAnswer execute(StartCommand cmd) { existingVmName = existingVmInDc.getName(); existingVmFileInfo = existingVmInDc.getFileInfo(); existingVmFileLayout = existingVmInDc.getFileLayout(); + existingDatastores = existingVmInDc.getAllDatastores(); existingVmInDc.unregisterVm(); } Pair rootDiskDataStoreDetails = null; @@ -2072,7 +2074,18 @@ protected StartAnswer execute(StartCommand cmd) { // Since VM was successfully powered-on, if there was an existing VM in a different cluster that was unregistered, delete all the files associated with it. if (existingVmName != null && existingVmFileLayout != null) { - deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true); + List vmDatastoreNames = new ArrayList(); + for (DatastoreMO vmDatastore : vmMo.getAllDatastores()) { + vmDatastoreNames.add(vmDatastore.getName()); + } + // Don't delete files that are in a datastore that is being used by the new VM as well (zone-wide datastore). + List skipDatastores = new ArrayList(); + for (DatastoreMO existingDatastore : existingDatastores) { + if (vmDatastoreNames.contains(existingDatastore.getName())) { + skipDatastores.add(existingDatastore.getName()); + } + } + deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true, skipDatastores); } return startAnswer; @@ -2701,7 +2714,7 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v } } - private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks) throws Exception { + private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks, List skipDatastores) throws Exception { s_logger.debug("Deleting files associated with an existing VM that was unregistered"); DatastoreFile vmFolder = null; try { @@ -2714,8 +2727,10 @@ private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, else if (file.getType().equals("config")) vmFolder = new DatastoreFile(fileInDatastore.getDatastoreName(), fileInDatastore.getDir()); DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); - s_logger.debug("Deleting file: " + file.getName()); - dsMo.deleteFile(file.getName(), dcMo.getMor(), true); + if (skipDatastores == null || !skipDatastores.contains(dsMo.getName())) { + s_logger.debug("Deleting file: " + file.getName()); + dsMo.deleteFile(file.getName(), dcMo.getMor(), true); + } } // Delete files that are present in the VM folder - this will take care of the VM disks as well. DatastoreMO vmFolderDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(vmFolder.getDatastoreName())); @@ -2723,14 +2738,18 @@ else if (file.getType().equals("config")) if (deleteDisks) { for (String file : files) { String vmDiskFileFullPath = String.format("%s/%s", vmFolder.getPath(), file); - s_logger.debug("Deleting file: " + vmDiskFileFullPath); - vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true); + if (skipDatastores == null || !skipDatastores.contains(vmFolderDsMo.getName())) { + s_logger.debug("Deleting file: " + vmDiskFileFullPath); + vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true); + } } } // Delete VM folder if (deleteDisks || files.length == 0) { - s_logger.debug("Deleting folder: " + vmFolder.getPath()); - vmFolderDsMo.deleteFolder(vmFolder.getPath(), dcMo.getMor()); + if (skipDatastores == null || !skipDatastores.contains(vmFolderDsMo.getName())) { + s_logger.debug("Deleting folder: " + vmFolder.getPath()); + vmFolderDsMo.deleteFolder(vmFolder.getPath(), dcMo.getMor()); + } } } catch (Exception e) { String message = "Failed to delete files associated with an existing VM that was unregistered due to " + VmwareHelper.getExceptionMessage(e); @@ -4556,7 +4575,7 @@ protected Answer execute(UnregisterVMCommand cmd) { VirtualMachineFileLayoutEx vmFileLayout = vmMo.getFileLayout(); context.getService().unregisterVM(vmMo.getMor()); if (cmd.getCleanupVmFiles()) { - deleteUnregisteredVmFiles(vmFileLayout, dataCenterMo, false); + deleteUnregisteredVmFiles(vmFileLayout, dataCenterMo, false, null); } return new Answer(cmd, true, "unregister succeeded"); } catch (Exception e) { diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 3cf3ad1744fe..f32f080c1645 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -34,6 +34,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.apache.commons.collections.CollectionUtils; import org.apache.log4j.Logger; import com.google.gson.Gson; @@ -902,6 +903,38 @@ else if (prop.getName().startsWith("value[")) { return networks; } + public List getAllDatastores() throws Exception { + PropertySpec pSpec = new PropertySpec(); + pSpec.setType("Datastore"); + pSpec.getPathSet().add("name"); + + TraversalSpec vmDatastoreTraversal = new TraversalSpec(); + vmDatastoreTraversal.setType("VirtualMachine"); + vmDatastoreTraversal.setPath("datastore"); + vmDatastoreTraversal.setName("vmDatastoreTraversal"); + + ObjectSpec oSpec = new ObjectSpec(); + oSpec.setObj(_mor); + oSpec.setSkip(Boolean.TRUE); + oSpec.getSelectSet().add(vmDatastoreTraversal); + + PropertyFilterSpec pfSpec = new PropertyFilterSpec(); + pfSpec.getPropSet().add(pSpec); + pfSpec.getObjectSet().add(oSpec); + List pfSpecArr = new ArrayList(); + pfSpecArr.add(pfSpec); + + List ocs = _context.getService().retrieveProperties(_context.getPropertyCollector(), pfSpecArr); + + List datastores = new ArrayList(); + if (CollectionUtils.isNotEmpty(ocs)) { + for (ObjectContent oc : ocs) { + datastores.add(new DatastoreMO(_context, oc.getObj())); + } + } + return datastores; + } + /** * Retrieve path info to access VM files via vSphere web interface * @return [0] vm-name, [1] data-center-name, [2] datastore-name From 82cfd39feb510b71a8205bd31d6b3d65f7c83bc4 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 14 Aug 2018 12:50:48 +0530 Subject: [PATCH 2/4] refactor common changes to a method --- .../vmware/resource/VmwareResource.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 5d56274d8653..d52959d316e4 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2953,6 +2953,13 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v } } } + + private void checkAndDeleteDatastoreFile(String filePath, List skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) { + if (dsMo != null && dcMo != null && (skipDatastores == null || !skipDatastores.contains(dsMo.getName()))) { + s_logger.debug("Deleting file: " + filePath); + dsMo.deleteFile(filePath, dcMo.getMor(), true); + } + } private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks, List skipDatastores) throws Exception { s_logger.debug("Deleting files associated with an existing VM that was unregistered"); @@ -2967,10 +2974,7 @@ private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, else if (file.getType().equals("config")) vmFolder = new DatastoreFile(fileInDatastore.getDatastoreName(), fileInDatastore.getDir()); DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); - if (skipDatastores == null || !skipDatastores.contains(dsMo.getName())) { - s_logger.debug("Deleting file: " + file.getName()); - dsMo.deleteFile(file.getName(), dcMo.getMor(), true); - } + checkAndDeleteDatastoreFile(file.getName(), skipDatastores, dsMo, dcMo); } // Delete files that are present in the VM folder - this will take care of the VM disks as well. DatastoreMO vmFolderDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(vmFolder.getDatastoreName())); @@ -2978,18 +2982,12 @@ else if (file.getType().equals("config")) if (deleteDisks) { for (String file : files) { String vmDiskFileFullPath = String.format("%s/%s", vmFolder.getPath(), file); - if (skipDatastores == null || !skipDatastores.contains(vmFolderDsMo.getName())) { - s_logger.debug("Deleting file: " + vmDiskFileFullPath); - vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true); - } + checkAndDeleteDatastoreFile(vmDiskFileFullPath, skipDatastores, vmFolderDsMo, dcMo); } } // Delete VM folder if (deleteDisks || files.length == 0) { - if (skipDatastores == null || !skipDatastores.contains(vmFolderDsMo.getName())) { - s_logger.debug("Deleting folder: " + vmFolder.getPath()); - vmFolderDsMo.deleteFolder(vmFolder.getPath(), dcMo.getMor()); - } + checkAndDeleteDatastoreFile(vmFolder.getPath(), skipDatastores, vmFolderDsMo, dcMo); } } catch (Exception e) { String message = "Failed to delete files associated with an existing VM that was unregistered due to " + VmwareHelper.getExceptionMessage(e); From 43697f1cea19f2a79471cc1ebbcb5144ef15f715 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 14 Aug 2018 13:31:14 +0530 Subject: [PATCH 3/4] removing trailing whitespace --- .../com/cloud/hypervisor/vmware/resource/VmwareResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index d52959d316e4..62f8f04a4e03 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2953,7 +2953,7 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v } } } - + private void checkAndDeleteDatastoreFile(String filePath, List skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) { if (dsMo != null && dcMo != null && (skipDatastores == null || !skipDatastores.contains(dsMo.getName()))) { s_logger.debug("Deleting file: " + filePath); From d2746899139ec8ccc080e3dd19fff41bc6e29a21 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Tue, 14 Aug 2018 14:24:31 +0530 Subject: [PATCH 4/4] github editor boo boo - throw exception --- .../com/cloud/hypervisor/vmware/resource/VmwareResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index 62f8f04a4e03..e35a71566a17 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2954,7 +2954,7 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v } } - private void checkAndDeleteDatastoreFile(String filePath, List skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) { + private void checkAndDeleteDatastoreFile(String filePath, List skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception { if (dsMo != null && dcMo != null && (skipDatastores == null || !skipDatastores.contains(dsMo.getName()))) { s_logger.debug("Deleting file: " + filePath); dsMo.deleteFile(filePath, dcMo.getMor(), true);