You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by wi...@apache.org on 2015/01/02 15:36:35 UTC

[43/50] [abbrv] git commit: updated refs/heads/reporter to b26f3fc

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/reporter
Commit: 974b0180dd67f19fea921092105161f849891ac5
Parents: 7b32b8a
Author: Likitha Shetty <li...@citrix.com>
Authored: Mon Dec 8 18:59:51 2014 +0530
Committer: Likitha Shetty <li...@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");