Skip to content

Commit e9003fa

Browse files
sureshanapartirohityadavcloud
authored andcommitted
CLOUDSTACK-8609: [VMware] VM is not accessible after migration across clusters (#2091)
[VMware] VM is not accessible after migration across clusters. Once a VM is successfully started, don't delete the files associated with the unregistered VM, if the files are in a storage that is being used by the new VM. Attempt to unregister a VM in another DC, only if there is a host associated with a VM. This closes #556
1 parent 4b33764 commit e9003fa

File tree

2 files changed

+59
-9
lines changed

2 files changed

+59
-9
lines changed

plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,6 +1668,7 @@ protected StartAnswer execute(StartCommand cmd) {
16681668
String existingVmName = null;
16691669
VirtualMachineFileInfo existingVmFileInfo = null;
16701670
VirtualMachineFileLayoutEx existingVmFileLayout = null;
1671+
List<DatastoreMO> existingDatastores = new ArrayList<DatastoreMO>();
16711672

16721673
Pair<String, String> names = composeVmNames(vmSpec);
16731674
String vmInternalCSName = names.first();
@@ -1790,6 +1791,7 @@ protected StartAnswer execute(StartCommand cmd) {
17901791
existingVmName = existingVmInDc.getName();
17911792
existingVmFileInfo = existingVmInDc.getFileInfo();
17921793
existingVmFileLayout = existingVmInDc.getFileLayout();
1794+
existingDatastores = existingVmInDc.getAllDatastores();
17931795
existingVmInDc.unregisterVm();
17941796
}
17951797
Pair<ManagedObjectReference, DatastoreMO> rootDiskDataStoreDetails = null;
@@ -2256,7 +2258,18 @@ protected StartAnswer execute(StartCommand cmd) {
22562258

22572259
// 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.
22582260
if (existingVmName != null && existingVmFileLayout != null) {
2259-
deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true);
2261+
List<String> vmDatastoreNames = new ArrayList<String>();
2262+
for (DatastoreMO vmDatastore : vmMo.getAllDatastores()) {
2263+
vmDatastoreNames.add(vmDatastore.getName());
2264+
}
2265+
// Don't delete files that are in a datastore that is being used by the new VM as well (zone-wide datastore).
2266+
List<String> skipDatastores = new ArrayList<String>();
2267+
for (DatastoreMO existingDatastore : existingDatastores) {
2268+
if (vmDatastoreNames.contains(existingDatastore.getName())) {
2269+
skipDatastores.add(existingDatastore.getName());
2270+
}
2271+
}
2272+
deleteUnregisteredVmFiles(existingVmFileLayout, dcMo, true, skipDatastores);
22602273
}
22612274

22622275
return startAnswer;
@@ -2944,7 +2957,14 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v
29442957
}
29452958
}
29462959

2947-
private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks) throws Exception {
2960+
private void checkAndDeleteDatastoreFile(String filePath, List<String> skipDatastores, DatastoreMO dsMo, DatacenterMO dcMo) throws Exception {
2961+
if (dsMo != null && dcMo != null && (skipDatastores == null || !skipDatastores.contains(dsMo.getName()))) {
2962+
s_logger.debug("Deleting file: " + filePath);
2963+
dsMo.deleteFile(filePath, dcMo.getMor(), true);
2964+
}
2965+
}
2966+
2967+
private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout, DatacenterMO dcMo, boolean deleteDisks, List<String> skipDatastores) throws Exception {
29482968
s_logger.debug("Deleting files associated with an existing VM that was unregistered");
29492969
DatastoreFile vmFolder = null;
29502970
try {
@@ -2957,23 +2977,20 @@ private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx vmFileLayout,
29572977
else if (file.getType().equals("config"))
29582978
vmFolder = new DatastoreFile(fileInDatastore.getDatastoreName(), fileInDatastore.getDir());
29592979
DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName()));
2960-
s_logger.debug("Deleting file: " + file.getName());
2961-
dsMo.deleteFile(file.getName(), dcMo.getMor(), true, VmwareManager.s_vmwareSearchExcludeFolder.value());
2980+
checkAndDeleteDatastoreFile(file.getName(), skipDatastores, dsMo, dcMo);
29622981
}
29632982
// Delete files that are present in the VM folder - this will take care of the VM disks as well.
29642983
DatastoreMO vmFolderDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(vmFolder.getDatastoreName()));
29652984
String[] files = vmFolderDsMo.listDirContent(vmFolder.getPath());
29662985
if (deleteDisks) {
29672986
for (String file : files) {
29682987
String vmDiskFileFullPath = String.format("%s/%s", vmFolder.getPath(), file);
2969-
s_logger.debug("Deleting file: " + vmDiskFileFullPath);
2970-
vmFolderDsMo.deleteFile(vmDiskFileFullPath, dcMo.getMor(), true, VmwareManager.s_vmwareSearchExcludeFolder.value());
2988+
checkAndDeleteDatastoreFile(vmDiskFileFullPath, skipDatastores, vmFolderDsMo, dcMo);
29712989
}
29722990
}
29732991
// Delete VM folder
29742992
if (deleteDisks || files.length == 0) {
2975-
s_logger.debug("Deleting folder: " + vmFolder.getPath());
2976-
vmFolderDsMo.deleteFolder(vmFolder.getPath(), dcMo.getMor());
2993+
checkAndDeleteDatastoreFile(vmFolder.getPath(), skipDatastores, vmFolderDsMo, dcMo);
29772994
}
29782995
} catch (Exception e) {
29792996
String message = "Failed to delete files associated with an existing VM that was unregistered due to " + VmwareHelper.getExceptionMessage(e);
@@ -4908,7 +4925,7 @@ protected Answer execute(UnregisterVMCommand cmd) {
49084925
VirtualMachineFileLayoutEx vmFileLayout = vmMo.getFileLayout();
49094926
context.getService().unregisterVM(vmMo.getMor());
49104927
if (cmd.getCleanupVmFiles()) {
4911-
deleteUnregisteredVmFiles(vmFileLayout, dataCenterMo, false);
4928+
deleteUnregisteredVmFiles(vmFileLayout, dataCenterMo, false, null);
49124929
}
49134930
return new Answer(cmd, true, "unregister succeeded");
49144931
} catch (Exception e) {

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.util.concurrent.Executors;
3535
import java.util.concurrent.Future;
3636

37+
import org.apache.commons.collections.CollectionUtils;
3738
import org.apache.log4j.Logger;
3839

3940
import com.google.gson.Gson;
@@ -932,6 +933,38 @@ else if (prop.getName().startsWith("value[")) {
932933
return networks;
933934
}
934935

936+
public List<DatastoreMO> getAllDatastores() throws Exception {
937+
PropertySpec pSpec = new PropertySpec();
938+
pSpec.setType("Datastore");
939+
pSpec.getPathSet().add("name");
940+
941+
TraversalSpec vmDatastoreTraversal = new TraversalSpec();
942+
vmDatastoreTraversal.setType("VirtualMachine");
943+
vmDatastoreTraversal.setPath("datastore");
944+
vmDatastoreTraversal.setName("vmDatastoreTraversal");
945+
946+
ObjectSpec oSpec = new ObjectSpec();
947+
oSpec.setObj(_mor);
948+
oSpec.setSkip(Boolean.TRUE);
949+
oSpec.getSelectSet().add(vmDatastoreTraversal);
950+
951+
PropertyFilterSpec pfSpec = new PropertyFilterSpec();
952+
pfSpec.getPropSet().add(pSpec);
953+
pfSpec.getObjectSet().add(oSpec);
954+
List<PropertyFilterSpec> pfSpecArr = new ArrayList<PropertyFilterSpec>();
955+
pfSpecArr.add(pfSpec);
956+
957+
List<ObjectContent> ocs = _context.getService().retrieveProperties(_context.getPropertyCollector(), pfSpecArr);
958+
959+
List<DatastoreMO> datastores = new ArrayList<DatastoreMO>();
960+
if (CollectionUtils.isNotEmpty(ocs)) {
961+
for (ObjectContent oc : ocs) {
962+
datastores.add(new DatastoreMO(_context, oc.getObj()));
963+
}
964+
}
965+
return datastores;
966+
}
967+
935968
/**
936969
* Retrieve path info to access VM files via vSphere web interface
937970
* @return [0] vm-name, [1] data-center-name, [2] datastore-name

0 commit comments

Comments
 (0)