Repository: cloudstack
Updated Branches:
  refs/heads/master 7b32b8a26 -> 974b0180d


CLOUDSTACK-8126. Cold Migration of VM is not working as expected. In case a VM 
is cold migrated across clusters then VM fails to start.
1. If a VM by the same name exists on a different cluster in the VMware DC, 
unregister the existing VM and continue with the VM start.
2. If VM start succeeds, delete VM files associated with the unregistered VM.
3. If VM start fails, re-register the unregistered VM.


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/974b0180
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/974b0180
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/974b0180

Branch: refs/heads/master
Commit: 974b0180dd67f19fea921092105161f849891ac5
Parents: 7b32b8a
Author: Likitha Shetty <likitha.she...@citrix.com>
Authored: Mon Dec 8 18:59:51 2014 +0530
Committer: Likitha Shetty <likitha.she...@citrix.com>
Committed: Wed Dec 24 15:07:08 2014 +0530

----------------------------------------------------------------------
 .../vmware/resource/VmwareResource.java         | 77 +++++++++++++++++++-
 .../hypervisor/vmware/mo/VirtualMachineMO.java  | 36 +++++++++
 2 files changed, 111 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/974b0180/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
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 53cdb99..0dfde45 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
@@ -84,6 +84,9 @@ import com.vmware.vim25.VirtualEthernetCard;
 import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo;
 import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo;
 import com.vmware.vim25.VirtualMachineConfigSpec;
+import com.vmware.vim25.VirtualMachineFileInfo;
+import com.vmware.vim25.VirtualMachineFileLayoutEx;
+import com.vmware.vim25.VirtualMachineFileLayoutExFileInfo;
 import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
 import com.vmware.vim25.VirtualMachinePowerState;
 import com.vmware.vim25.VirtualMachineRelocateSpec;
@@ -1326,17 +1329,22 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
         VirtualMachineTO vmSpec = cmd.getVirtualMachine();
         boolean vmAlreadyExistsInVcenter = false;
 
+        String existingVmName = null;
+        VirtualMachineFileInfo existingVmFileInfo = null;
+        VirtualMachineFileLayoutEx existingVmFileLayout = null;
+
         Pair<String, String> names = composeVmNames(vmSpec);
         String vmInternalCSName = names.first();
         String vmNameOnVcenter = names.second();
 
         // Thus, vmInternalCSName always holds i-x-y, the cloudstack generated 
internal VM name.
         VmwareContext context = getServiceContext();
+        DatacenterMO dcMo = null;
         try {
             VmwareManager mgr = 
context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
 
             VmwareHypervisorHost hyperHost = getHyperHost(context);
-            DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), 
hyperHost.getHyperHostDatacenter());
+            dcMo = new DatacenterMO(hyperHost.getContext(), 
hyperHost.getHyperHostDatacenter());
 
             // Validate VM name is unique in Datacenter
             VirtualMachineMO vmInVcenter = 
dcMo.checkIfVmAlreadyExistsInVcenter(vmNameOnVcenter, vmInternalCSName);
@@ -1404,6 +1412,15 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
                         vmMo.tearDownDevices(new Class<?>[] 
{VirtualEthernetCard.class});
                     vmMo.ensureScsiDeviceController();
                 } else {
+                    // If a VM with the same name is found in a different 
cluster in the DC, unregister the old VM and configure a new VM 
(cold-migration).
+                    VirtualMachineMO existingVmInDc = 
dcMo.findVm(vmInternalCSName);
+                    if (existingVmInDc != null) {
+                        s_logger.debug("Found VM: " + vmInternalCSName + " on 
a host in a different cluster. Unregistering the exisitng VM.");
+                        existingVmName = existingVmInDc.getName();
+                        existingVmFileInfo = existingVmInDc.getFileInfo();
+                        existingVmFileLayout = existingVmInDc.getFileLayout();
+                        existingVmInDc.unregisterVm();
+                    }
                     Pair<ManagedObjectReference, DatastoreMO> 
rootDiskDataStoreDetails = null;
                     for (DiskTO vol : disks) {
                         if (vol.getType() == Volume.Type.ROOT) {
@@ -1429,7 +1446,9 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
 
                     assert (vmSpec.getMinSpeed() != null) && 
(rootDiskDataStoreDetails != null);
 
-                    if 
(rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", 
rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter)) {
+                    boolean vmFolderExists = 
rootDiskDataStoreDetails.second().folderExists(String.format("[%s]", 
rootDiskDataStoreDetails.second().getName()), vmNameOnVcenter);
+                    String vmxFileFullPath = 
dsRootVolumeIsOn.searchFileInSubFolders(vmNameOnVcenter + ".vmx", false);
+                    if (vmFolderExists && vmxFileFullPath != null) { // VM can 
be registered only if .vmx is present.
                         registerVm(vmNameOnVcenter, dsRootVolumeIsOn);
                         vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName);
                         tearDownVm(vmMo);
@@ -1740,6 +1759,11 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
 
             startAnswer.setIqnToPath(iqnToPath);
 
+            // 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);
+            }
+
             return startAnswer;
         } catch (Throwable e) {
             if (e instanceof RemoteException) {
@@ -1753,6 +1777,20 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
             if(vmAlreadyExistsInVcenter) {
                 startAnswer.setContextParam("stopRetry", "true");
             }
+
+            // Since VM start failed, if there was an existing VM in a 
different cluster that was unregistered, register it back.
+            if (existingVmName != null && existingVmFileInfo != null) {
+                s_logger.debug("Since VM start failed, registering back an 
existing VM: " + existingVmName + " that was unregistered");
+                try {
+                    DatastoreFile fileInDatastore = new 
DatastoreFile(existingVmFileInfo.getVmPathName());
+                    DatastoreMO existingVmDsMo = new 
DatastoreMO(dcMo.getContext(), 
dcMo.findDatastore(fileInDatastore.getDatastoreName()));
+                    registerVm(existingVmName, existingVmDsMo);
+                } catch (Exception ex){
+                    String message = "Failed to register an existing VM: " + 
existingVmName + " due to " + VmwareHelper.getExceptionMessage(ex);
+                    s_logger.warn(message, ex);
+                }
+            }
+
             return startAnswer;
         } finally {
         }
@@ -2201,6 +2239,41 @@ public class VmwareResource implements 
StoragePoolResource, ServerResource, Vmwa
         }
     }
 
+    private void deleteUnregisteredVmFiles(VirtualMachineFileLayoutEx 
vmFileLayout, DatacenterMO dcMo) throws Exception {
+        s_logger.debug("Deleting files associated with an existing VM that was 
unregistered");
+        DatastoreFile vmFolder = null;
+        try {
+            List<VirtualMachineFileLayoutExFileInfo> fileInfo = 
vmFileLayout.getFile();
+            for (VirtualMachineFileLayoutExFileInfo file : fileInfo) {
+                DatastoreFile fileInDatastore = new 
DatastoreFile(file.getName());
+                // In case of linked clones, VM file layout includes the base 
disk so don't delete all disk files.
+                if (file.getType().startsWith("disk") || 
file.getType().startsWith("digest"))
+                    continue;
+                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);
+            }
+            // 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()));
+            String[] files = vmFolderDsMo.listDirContent(vmFolder.getPath());
+            if (files.length != 0) {
+                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);
+                }
+            }
+            // Delete VM folder
+            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);
+            s_logger.warn(message, e);
+        }
+    }
+
     private static VolumeObjectTO getVolumeInSpec(VirtualMachineTO vmSpec, 
VolumeObjectTO srcVol) {
         for (DiskTO disk : vmSpec.getDisks()) {
             VolumeObjectTO vol = (VolumeObjectTO)disk.getData();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/974b0180/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
----------------------------------------------------------------------
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 286aedd..5f180e1 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -86,6 +86,7 @@ import com.vmware.vim25.VirtualMachineConfigOption;
 import com.vmware.vim25.VirtualMachineConfigSpec;
 import com.vmware.vim25.VirtualMachineConfigSummary;
 import com.vmware.vim25.VirtualMachineFileInfo;
+import com.vmware.vim25.VirtualMachineFileLayoutEx;
 import com.vmware.vim25.VirtualMachineMessage;
 import com.vmware.vim25.VirtualMachineMovePriority;
 import com.vmware.vim25.VirtualMachinePowerState;
@@ -740,6 +741,41 @@ public class VirtualMachineMO extends BaseMO {
         return 
(VirtualMachineFileInfo)_context.getVimClient().getDynamicProperty(_mor, 
"config.files");
     }
 
+    public VirtualMachineFileLayoutEx getFileLayout() throws Exception {
+        VirtualMachineFileLayoutEx fileLayout = null;
+        PropertySpec pSpec = new PropertySpec();
+        pSpec.setType("VirtualMachine");
+        pSpec.getPathSet().add("layoutEx");
+
+        ObjectSpec oSpec = new ObjectSpec();
+        oSpec.setObj(_mor);
+        oSpec.setSkip(Boolean.FALSE);
+
+        PropertyFilterSpec pfSpec = new PropertyFilterSpec();
+        pfSpec.getPropSet().add(pSpec);
+        pfSpec.getObjectSet().add(oSpec);
+        List<PropertyFilterSpec> pfSpecArr = new 
ArrayList<PropertyFilterSpec>();
+        pfSpecArr.add(pfSpec);
+
+        List<ObjectContent> ocs = 
_context.getService().retrieveProperties(_context.getPropertyCollector(), 
pfSpecArr);
+
+        if (ocs != null) {
+            for (ObjectContent oc : ocs) {
+                List<DynamicProperty> props = oc.getPropSet();
+                if (props != null) {
+                    for (DynamicProperty prop : props) {
+                        if (prop.getName().equals("layoutEx")) {
+                            fileLayout = 
(VirtualMachineFileLayoutEx)prop.getVal();
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        return fileLayout;
+    }
+
     @Override
     public ManagedObjectReference getParentMor() throws Exception {
         return 
(ManagedObjectReference)_context.getVimClient().getDynamicProperty(_mor, 
"parent");

Reply via email to