diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java index b77c7fc6306..e7f6260fcb6 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/guru/VMwareGuru.java @@ -416,14 +416,6 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru { return tokens[0] + "@" + vCenterIp; } - @Override - public List finalizeExpunge(VirtualMachine vm) { - UnregisterVMCommand unregisterVMCommand = new UnregisterVMCommand(vm.getInstanceName()); - List commands = new ArrayList(); - commands.add(unregisterVMCommand); - return commands; - } - @Override public List finalizeExpungeNics(VirtualMachine vm, List nics) { List commands = new ArrayList(); diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java index d60abad3519..20544df3d06 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.storage.resource; +import java.util.List; + import org.apache.log4j.Logger; import com.cloud.hypervisor.vmware.mo.DatacenterMO; @@ -166,6 +168,40 @@ public class VmwareStorageLayoutHelper { s_logger.info("Fixup folder-synchronization. move " + fileDsFullPath + " -> " + targetPath); ds.moveDatastoreFile(fileDsFullPath, dcMo.getMor(), ds.getMor(), targetPath, dcMo.getMor(), true); } + + public static void moveVolumeToRootFolder(DatacenterMO dcMo, List detachedDisks) throws Exception { + if(detachedDisks.size() > 0) { + for(String fileFullDsPath : detachedDisks) { + DatastoreFile file = new DatastoreFile(fileFullDsPath); + + s_logger.info("Check if we need to move " + fileFullDsPath + " to its root location"); + DatastoreMO dsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(file.getDatastoreName())); + if(dsMo.getMor() != null) { + DatastoreFile targetFile = new DatastoreFile(file.getDatastoreName(), file.getFileName()); + if(!targetFile.getPath().equalsIgnoreCase(file.getPath())) { + s_logger.info("Move " + file.getPath() + " -> " + targetFile.getPath()); + dsMo.moveDatastoreFile(file.getPath(), dcMo.getMor(), dsMo.getMor(), targetFile.getPath(), dcMo.getMor(), true); + + String pairSrcFilePath = file.getCompanionPath(file.getFileBaseName() + "-flat.vmdk"); + String pairTargetFilePath = targetFile.getCompanionPath(file.getFileBaseName() + "-flat.vmdk"); + if(dsMo.fileExists(pairSrcFilePath)) { + s_logger.info("Move " + pairSrcFilePath + " -> " + pairTargetFilePath); + dsMo.moveDatastoreFile(pairSrcFilePath, dcMo.getMor(), dsMo.getMor(), pairTargetFilePath, dcMo.getMor(), true); + } + + pairSrcFilePath = file.getCompanionPath(file.getFileBaseName() + "-delta.vmdk"); + pairTargetFilePath = targetFile.getCompanionPath(file.getFileBaseName() + "-delta.vmdk"); + if(dsMo.fileExists(pairSrcFilePath)) { + s_logger.info("Move " + pairSrcFilePath + " -> " + pairTargetFilePath); + dsMo.moveDatastoreFile(pairSrcFilePath, dcMo.getMor(), dsMo.getMor(), pairTargetFilePath, dcMo.getMor(), true); + } + } + } else { + s_logger.warn("Datastore for " + fileFullDsPath + " no longer exists, we have to skip"); + } + } + } + } public static String getTemplateOnSecStorageFilePath(String secStorageMountPoint, String templateRelativeFolderPath, String templateName, String fileExtension) { @@ -227,7 +263,7 @@ public class VmwareStorageLayoutHelper { if(!dsMo.fileExists(fileFullPath)) fileFullPath = dsMo.searchFileInSubFolders(fileName, false); if(fileFullPath != null) { - dsMo.deleteFile(fileFullPath, dcMo.getMor(), false); + dsMo.deleteFile(fileFullPath, dcMo.getMor(), true); } else { s_logger.warn("Unable to locate VMDK file: " + fileName); } @@ -237,7 +273,7 @@ public class VmwareStorageLayoutHelper { if(!dsMo.fileExists(fileFullPath)) fileFullPath = dsMo.searchFileInSubFolders(fileName, false); if(fileFullPath != null) { - dsMo.deleteFile(fileFullPath, dcMo.getMor(), false); + dsMo.deleteFile(fileFullPath, dcMo.getMor(), true); } else { s_logger.warn("Unable to locate VMDK file: " + fileName); } @@ -247,7 +283,7 @@ public class VmwareStorageLayoutHelper { if(!dsMo.fileExists(fileFullPath)) fileFullPath = dsMo.searchFileInSubFolders(fileName, false); if(fileFullPath != null) { - dsMo.deleteFile(fileFullPath, dcMo.getMor(), false); + dsMo.deleteFile(fileFullPath, dcMo.getMor(), true); } else { s_logger.warn("Unable to locate VMDK file: " + fileName); } diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java index 65a4a468a24..83a9531fd10 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java +++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java @@ -71,6 +71,7 @@ import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper; import com.cloud.hypervisor.vmware.mo.NetworkDetails; +import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfo; import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost; import com.cloud.hypervisor.vmware.resource.VmwareResource; @@ -1308,7 +1309,7 @@ public class VmwareStorageProcessor implements StorageProcessor { } else { try{ vmMo.unmountToolsInstaller(); - }catch(Throwable e){ + } catch(Throwable e){ vmMo.detachIso(null); } } @@ -1447,18 +1448,6 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd)); } - /* - * DestroyCommand content example - * - * {"volume": {"id":5,"name":"Volume1", "mountPoint":"/export/home/kelven/vmware-test/primary", - * "path":"6bb8762f-c34c-453c-8e03-26cc246ceec4", "size":0,"type":"DATADISK","resourceType": - * "STORAGE_POOL","storagePoolType":"NetworkFilesystem", "poolId":0,"deviceId":0 } } - * - * {"volume": {"id":1, "name":"i-2-1-KY-ROOT", "mountPoint":"/export/home/kelven/vmware-test/primary", - * "path":"i-2-1-KY-ROOT","size":0,"type":"ROOT", "resourceType":"STORAGE_POOL", "storagePoolType":"NetworkFilesystem", - * "poolId":0,"deviceId":0 } } - */ - try { VmwareContext context = hostService.getServiceContext(null); VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, null); @@ -1479,6 +1468,7 @@ public class VmwareStorageProcessor implements StorageProcessor { ClusterMO clusterMo = new ClusterMO(context, morCluster); if (vol.getVolumeType() == Volume.Type.ROOT) { + String vmName = vol.getVmName(); if (vmName != null) { VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName); @@ -1487,6 +1477,14 @@ public class VmwareStorageProcessor implements StorageProcessor { s_logger.info("Destroy root volume and VM itself. vmName " + vmName); } + // Remove all snapshots to consolidate disks for removal + vmMo.removeAllSnapshots(); + + VirtualMachineDiskInfo diskInfo = null; + if(vol.getChainInfo() != null) + diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class); + + HostMO hostMo = vmMo.getRunningHost(); List networks = vmMo.getNetworksWithDetails(); @@ -1494,7 +1492,12 @@ public class VmwareStorageProcessor implements StorageProcessor { if (this.resource.getVmState(vmMo) != State.Stopped) { vmMo.safePowerOff(_shutdown_waitMs); } - vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); + + List detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null); + VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks); + + // let vmMo.destroy to delete volume for us + // vmMo.tearDownDevices(new Class[] { VirtualDisk.class, VirtualEthernetCard.class }); vmMo.destroy(); for (NetworkDetails netDetails : networks) { @@ -1506,10 +1509,13 @@ public class VmwareStorageProcessor implements StorageProcessor { } } - if (s_logger.isInfoEnabled()) +/* + if (s_logger.isInfoEnabled()) { s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk"); - - VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc)); + } + + VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc)); +*/ return new Answer(cmd, true, "Success"); } 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 e2a20e6fde9..a461a79c746 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -991,13 +991,11 @@ public class VirtualMachineMO extends BaseMO { VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, getScsiDeviceControllerKey(), vmdkDatastorePathChain, morDs, -1, 1); VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); deviceConfigSpec.setDevice(newDisk); deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); @@ -1024,13 +1022,11 @@ public class VirtualMachineMO extends BaseMO { VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, controllerKey, vmdkDatastorePathChain, -1, 1); VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); deviceConfigSpec.setDevice(newDisk); deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); - //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); @@ -1067,7 +1063,6 @@ public class VirtualMachineMO extends BaseMO { List> chain = getDiskDatastorePathChain(deviceInfo.first(), true); VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); - //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1]; VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); deviceConfigSpec.setDevice(deviceInfo.first()); @@ -1076,7 +1071,6 @@ public class VirtualMachineMO extends BaseMO { } deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.REMOVE); - //deviceConfigSpecArray[0] = deviceConfigSpec; reConfigSpec.getDeviceChange().add(deviceConfigSpec); ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); @@ -1964,6 +1958,50 @@ public class VirtualMachineMO extends BaseMO { throw new Exception("Unable to find device controller"); } + public List detachAllDisksExcept(String vmdkBaseName, String deviceBusName) throws Exception { + List devices = (List)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + + VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); + List detachedDiskFiles = new ArrayList(); + + for(VirtualDevice device : devices) { + if(device instanceof VirtualDisk) { + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo)device.getBacking(); + + DatastoreFile dsBackingFile = new DatastoreFile(diskBackingInfo.getFileName()); + String backingBaseName = dsBackingFile.getFileBaseName(); + String deviceNumbering = getDeviceBusName(devices, device); + if(backingBaseName.equalsIgnoreCase(vmdkBaseName) || (deviceBusName != null && deviceBusName.equals(deviceNumbering))) { + continue; + } else { + s_logger.info("Detach " + diskBackingInfo.getFileName() + " from " + getName()); + + detachedDiskFiles.add(diskBackingInfo.getFileName()); + + deviceConfigSpec.setDevice(device); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.REMOVE); + + reConfigSpec.getDeviceChange().add(deviceConfigSpec); + } + } + } + + if(detachedDiskFiles.size() > 0) { + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); + boolean result = _context.getVimClient().waitForTask(morTask); + if(result) { + _context.waitForTaskProgressDone(morTask); + } else { + s_logger.warn("Unable to reconfigure the VM to detach disks"); + throw new Exception("Unable to reconfigure the VM to detach disks"); + } + } + + return detachedDiskFiles; + } + public VirtualDisk[] getAllDiskDevice() throws Exception { List deviceList = new ArrayList(); List devices = (List)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");