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();