From 2976d9c7932ed160cf3205c06f4d82efdfa0f10a Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Fri, 4 Oct 2013 15:59:08 -0700 Subject: [PATCH] CLOUDSTACK-4802: Change VM start flow to better support VM snapshot on certian version of vSphere, (vSphere 5.0 Update 2). If we detect that VM has pending VM snapshot, we will fully honor VM disk info from vCenter, since in some version of vSphere (vSphere 5.0 U2) does not allow disk-editting when VM has pending snapshot. --- .../vmware/resource/VmwareResource.java | 78 ++++++++++++------- .../vmware/mo/VirtualMachineMO.java | 28 ++++++- 2 files changed, 75 insertions(+), 31 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 de2eb9bebc5..464fd20671c 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -2661,6 +2661,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa DatacenterMO dcMo = new DatacenterMO(hyperHost.getContext(), hyperHost.getHyperHostDatacenter()); VirtualMachineDiskInfoBuilder diskInfoBuilder = null; VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmInternalCSName); + boolean hasSnapshot = false; if (vmMo != null) { s_logger.info("VM " + vmInternalCSName + " already exists, tear down devices for reconfiguration"); if (getVmState(vmMo) != State.Stopped) @@ -2668,7 +2669,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // retrieve disk information before we tear down diskInfoBuilder = vmMo.getDiskInfoBuilder(); - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + hasSnapshot = vmMo.hasSnapshot(); + if(!hasSnapshot) + vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + else + vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); vmMo.ensureScsiDeviceController(); } else { ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter(); @@ -2686,7 +2691,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa vmMo.safePowerOff(_shutdown_waitMs); diskInfoBuilder = vmMo.getDiskInfoBuilder(); - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + hasSnapshot = vmMo.hasSnapshot(); + if(!hasSnapshot) + vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + else + vmMo.tearDownDevices(new Class[] { VirtualEthernetCard.class }); vmMo.ensureScsiDeviceController(); } else { Pair rootDiskDataStoreDetails = null; @@ -2840,37 +2849,45 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // DiskTO[] sortedDisks = sortVolumesByDeviceId(disks); for (DiskTO vol : sortedDisks) { - deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - if (vol.getType() == Volume.Type.ISO) continue; - + VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol); controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey); - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); - PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore(); - Pair volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid()); - assert (volumeDsDetails != null); - VirtualDevice device; - - String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, - vol, matchingExistingDisk, - dataStoresDetails); - if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) - scsiUnitNumber++; - device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, - diskChain, - volumeDsDetails.first(), - (controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1); - - deviceConfigSpecArray[i].setDevice(device); - deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); - - if(s_logger.isDebugEnabled()) - s_logger.debug("Prepare volume at new device " + _gson.toJson(device)); - - i++; + if(!hasSnapshot) { + deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); + + VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore(); + Pair volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid()); + assert (volumeDsDetails != null); + + String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec, + vol, matchingExistingDisk, + dataStoresDetails); + if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + VirtualDevice device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey, + diskChain, + volumeDsDetails.first(), + (controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1); + + deviceConfigSpecArray[i].setDevice(device); + deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD); + + if(s_logger.isDebugEnabled()) + s_logger.debug("Prepare volume at new device " + _gson.toJson(device)); + + i++; + } else { + if(controllerKey == scsiControllerKey && VmwareHelper.isReservedScsiDeviceNumber(scsiUnitNumber)) + scsiUnitNumber++; + if(controllerKey == ideControllerKey) + ideUnitNumber++; + else + scsiUnitNumber++; + } } // @@ -2917,7 +2934,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa nicCount++; } - vmConfigSpec.getDeviceChange().addAll(Arrays.asList(deviceConfigSpecArray)); + for(int j = 0; j < i; j++) + vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[j]); // // Setup VM options @@ -5479,7 +5497,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa // tear down all devices first before we destroy the VM to avoid accidently delete disk backing files if (getVmState(vmMo) != State.Stopped) vmMo.safePowerOff(_shutdown_waitMs); - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + vmMo.tearDownDevices(new Class[] { /* VirtualDisk.class, */ VirtualEthernetCard.class }); vmMo.destroy(); for (NetworkDetails netDetails : networks) { 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 abc5bf8a8bf..55cc8de3a3d 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -577,6 +577,14 @@ public class VirtualMachineMO extends BaseMO { } return null; } + + public boolean hasSnapshot() throws Exception { + VirtualMachineSnapshotInfo info = getSnapshotInfo(); + if(info != null) { + return info.getCurrentSnapshot() != null; + } + return false; + } public boolean createFullClone(String cloneName, ManagedObjectReference morFolder, ManagedObjectReference morResourcePool, ManagedObjectReference morDs) throws Exception { @@ -1629,6 +1637,7 @@ public class VirtualMachineMO extends BaseMO { public void tearDownDevices(Class[] deviceClasses) throws Exception { VirtualDevice[] devices = getMatchedDevices(deviceClasses); + if(devices.length > 0) { VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[devices.length]; @@ -1637,9 +1646,9 @@ public class VirtualMachineMO extends BaseMO { deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); deviceConfigSpecArray[i].setDevice(devices[i]); deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.REMOVE); + vmConfigSpec.getDeviceChange().add(deviceConfigSpecArray[i]); } - vmConfigSpec.getDeviceChange().addAll(Arrays.asList(deviceConfigSpecArray)); if(!configureVm(vmConfigSpec)) { throw new Exception("Failed to detach devices"); } @@ -2021,6 +2030,10 @@ public class VirtualMachineMO extends BaseMO { return detachedDiskFiles; } + public List getAllDeviceList() throws Exception { + return (List)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + } + public VirtualDisk[] getAllDiskDevice() throws Exception { List deviceList = new ArrayList(); List devices = (List)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); @@ -2034,6 +2047,19 @@ public class VirtualMachineMO extends BaseMO { return deviceList.toArray(new VirtualDisk[0]); } + + public VirtualDisk getDiskDeviceByBusName(List allDevices, String busName) throws Exception { + for(VirtualDevice device : allDevices ) { + if(device instanceof VirtualDisk) { + VirtualDisk disk = (VirtualDisk)device; + String diskBusName = getDeviceBusName(allDevices, (VirtualDevice)disk); + if(busName.equalsIgnoreCase(diskBusName)) + return disk; + } + } + + return null; + } public VirtualDisk[] getAllIndependentDiskDevice() throws Exception { List independentDisks = new ArrayList();