From 3020df75f1c12a81633b167b9caf4a3d559b8f6f Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Fri, 11 May 2012 17:17:48 -0700 Subject: [PATCH] Add support routines for incremental snapshot support --- .../hypervisor/vmware/mo/TestVmwareMO.java | 42 +--- .../vmware/mo/SnapshotDescriptor.java | 155 ++++++++----- .../vmware/mo/VirtualMachineMO.java | 35 ++- .../hypervisor/vmware/util/VmwareHelper.java | 218 +++++++++++------- 4 files changed, 268 insertions(+), 182 deletions(-) mode change 100755 => 100644 core/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java mode change 100755 => 100644 vmware-base/src/com/cloud/hypervisor/vmware/mo/SnapshotDescriptor.java mode change 100755 => 100644 vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java mode change 100755 => 100644 vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java diff --git a/core/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java b/core/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java old mode 100755 new mode 100644 index 37f264c4d49..8cbc98a1d32 --- a/core/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java +++ b/core/test/com/cloud/hypervisor/vmware/mo/TestVmwareMO.java @@ -14,11 +14,13 @@ package com.cloud.hypervisor.vmware.mo; import java.util.GregorianCalendar; -import org.apache.log4j.Logger; - +import org.apache.log4j.Logger; + +import com.cloud.hypervisor.vmware.mo.SnapshotDescriptor.SnapshotInfo; import com.cloud.hypervisor.vmware.util.VmwareContext; import com.cloud.serializer.GsonHelper; -import com.cloud.utils.testcase.Log4jEnabledTestCase; +import com.cloud.utils.Pair; +import com.cloud.utils.testcase.Log4jEnabledTestCase; import com.google.gson.Gson; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.ManagedObjectReference; @@ -29,40 +31,6 @@ public class TestVmwareMO extends Log4jEnabledTestCase { private static final Logger s_logger = Logger.getLogger(TestVmwareMO.class); public void test() { - try { - VmwareContext context = TestVmwareContextFactory.create( - "10.223.80.29", "Administrator", "Suite219"); - - HostMO hostMo = new HostMO(context, "HostSystem", "host-10"); - ObjectContent[] ocs = hostMo.getVmPropertiesOnHyperHost(new String[] {"name", "config.template", "runtime.bootTime"}); - if(ocs != null) { - for(ObjectContent oc : ocs) { - DynamicProperty[] props = oc.getPropSet(); - if(props != null) { - String name = null; - boolean template = false; - GregorianCalendar bootTime = null; - - for(DynamicProperty prop : props) { - if(prop.getName().equals("name")) - name = prop.getVal().toString(); - else if(prop.getName().equals("config.template")) - template = (Boolean)prop.getVal(); - else if(prop.getName().equals("runtime.bootTime")) - bootTime = (GregorianCalendar)prop.getVal(); - } - - System.out.println("name: " + name + ", template: " + template + ", bootTime: " + bootTime); - - } - System.out.println(""); - } - } - - context.close(); - } catch(Exception e) { - s_logger.error("Unexpected exception : ", e); - } } } diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/SnapshotDescriptor.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/SnapshotDescriptor.java old mode 100755 new mode 100644 index ff5c1c26efa..531fa0736aa --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/SnapshotDescriptor.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/SnapshotDescriptor.java @@ -200,71 +200,98 @@ public class SnapshotDescriptor { info.setDisks(disks); info.setDisplayName(_properties.getProperty(String.format("snapshot%d.displayName", id))); l.add(info); + } + + current = _properties.getProperty(String.format("snapshot%d.parent", id)); + } + + return l.toArray(new SnapshotInfo[0]); + } + + public static class SnapshotInfo { + private int _id; + private String _displayName; + private int _numOfDisks; + private DiskInfo[] _disks; + + public SnapshotInfo() { + } + + public void setId(int id) { + _id = id; + } + + public int getId() { + return _id; + } + + public void setDisplayName(String name) { + _displayName = name; + } + + public String getDisplayName() { + return _displayName; + } + + public void setNumOfDisks(int numOfDisks) { + _numOfDisks = numOfDisks; + } + + public int getNumOfDisks() { + return _numOfDisks; + } + + public void setDisks(DiskInfo[] disks) { + _disks = disks; + } + + public DiskInfo[] getDisks() { + return _disks; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("SnapshotInfo : { id: "); + sb.append(_id); + sb.append(", displayName: ").append(_displayName); + sb.append(", numOfDisks: ").append(_numOfDisks); + sb.append(", disks: ["); + if(_disks != null) { + int i = 0; + for(DiskInfo diskInfo : _disks) { + if(i > 0) + sb.append(", "); + sb.append(diskInfo.toString()); + i++; + } } + sb.append("]}"); - current = _properties.getProperty(String.format("snapshot%d.parent", id)); + return sb.toString(); + } + } + + public static class DiskInfo { + private String _diskFileName; + private String _deviceName; + + public DiskInfo(String diskFileName, String deviceName) { + _diskFileName = diskFileName; + _deviceName = deviceName; + } + + public String getDiskFileName() { + return _diskFileName; + } + + public String getDeviceName() { + return _deviceName; } - - return l.toArray(new SnapshotInfo[0]); - } - - public static class SnapshotInfo { - private int _id; - private String _displayName; - private int _numOfDisks; - private DiskInfo[] _disks; - - public SnapshotInfo() { - } - - public void setId(int id) { - _id = id; - } - - public int getId() { - return _id; - } - - public void setDisplayName(String name) { - _displayName = name; - } - - public String getDisplayName() { - return _displayName; - } - - public void setNumOfDisks(int numOfDisks) { - _numOfDisks = numOfDisks; - } - - public int getNumOfDisks() { - return _numOfDisks; - } - - public void setDisks(DiskInfo[] disks) { - _disks = disks; - } - - public DiskInfo[] getDisks() { - return _disks; - } - } - public static class DiskInfo { - private String _diskFileName; - private String _deviceName; - - public DiskInfo(String diskFileName, String deviceName) { - _diskFileName = diskFileName; - _deviceName = deviceName; - } - - public String getDiskFileName() { - return _diskFileName; - } - - public String getDeviceName() { - return _deviceName; - } - } -} + @Override + public String toString() { + return "DiskInfo: { device: " + _deviceName + ", file: " + _diskFileName + " }"; + } + } +} diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java old mode 100755 new mode 100644 index 9ad279f935a..71907b0ced1 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -944,7 +944,40 @@ public class VirtualMachineMO extends BaseMO { s_logger.trace("vCenter API trace - attachDisk() done(successfully)"); } - // vmdkDatastorePath: [datastore name] vmdkFilePath + public void attachDisk(Pair[] vmdkDatastorePathChain, int controllerKey) throws Exception { + + if(s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.get_value() + ", vmdkDatastorePath: " + + new Gson().toJson(vmdkDatastorePathChain)); + + 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.setDeviceChange(deviceConfigSpecArray); + + ManagedObjectReference morTask = _context.getService().reconfigVM_Task(_mor, reConfigSpec); + String result = _context.getServiceUtil().waitForTask(morTask); + + if(!result.equals("sucess")) { + if(s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk() done(failed)"); + throw new Exception("Failed to attach disk due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + + _context.waitForTaskProgressDone(morTask); + + if(s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk() done(successfully)"); + } + + // vmdkDatastorePath: [datastore name] vmdkFilePath public List> detachDisk(String vmdkDatastorePath, boolean deleteBackingFile) throws Exception { if(s_logger.isTraceEnabled()) diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java old mode 100755 new mode 100644 index 0f717b82cc2..f328dd9a0b4 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -126,73 +126,73 @@ public class VmwareHelper { if(deviceNumber < 0) deviceNumber = vmMo.getNextDeviceNumber(controllerKey); disk.setControllerKey(controllerKey); - - disk.setKey(-contextNumber); - disk.setUnitNumber(deviceNumber); - disk.setCapacityInKB(sizeInMb*1024); - - VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); - connectInfo.setConnected(true); - connectInfo.setStartConnected(true); - disk.setConnectable(connectInfo); - - return disk; + + disk.setKey(-contextNumber); + disk.setUnitNumber(deviceNumber); + disk.setCapacityInKB(sizeInMb*1024); + + VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); + connectInfo.setConnected(true); + connectInfo.setStartConnected(true); + disk.setConnectable(connectInfo); + + return disk; } - - // vmdkDatastorePath: [datastore name] vmdkFilePath, create delta disk based on disk from template - public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePath, - int sizeInMb, ManagedObjectReference morDs, VirtualDisk templateDisk, int deviceNumber, int contextNumber) throws Exception { - - assert(templateDisk != null); - VirtualDeviceBackingInfo parentBacking = templateDisk.getBacking(); - assert(parentBacking != null); - - // TODO Not sure if we need to check if the disk in template and the new disk needs to share the - // same datastore - VirtualDisk disk = new VirtualDisk(); - if(parentBacking instanceof VirtualDiskFlatVer1BackingInfo) { - VirtualDiskFlatVer1BackingInfo backingInfo = new VirtualDiskFlatVer1BackingInfo(); - backingInfo.setDiskMode(((VirtualDiskFlatVer1BackingInfo)parentBacking).getDiskMode()); - backingInfo.setDatastore(morDs); - backingInfo.setFileName(vmdkDatastorePath); - backingInfo.setParent((VirtualDiskFlatVer1BackingInfo)parentBacking); - disk.setBacking(backingInfo); - } else if(parentBacking instanceof VirtualDiskFlatVer2BackingInfo) { - VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo(); - backingInfo.setDiskMode(((VirtualDiskFlatVer2BackingInfo)parentBacking).getDiskMode()); - backingInfo.setDatastore(morDs); - backingInfo.setFileName(vmdkDatastorePath); - backingInfo.setParent((VirtualDiskFlatVer2BackingInfo)parentBacking); - disk.setBacking(backingInfo); - } else if(parentBacking instanceof VirtualDiskRawDiskMappingVer1BackingInfo) { - VirtualDiskRawDiskMappingVer1BackingInfo backingInfo = new VirtualDiskRawDiskMappingVer1BackingInfo(); - backingInfo.setDiskMode(((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking).getDiskMode()); - backingInfo.setDatastore(morDs); - backingInfo.setFileName(vmdkDatastorePath); - backingInfo.setParent((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking); - disk.setBacking(backingInfo); - } else if(parentBacking instanceof VirtualDiskSparseVer1BackingInfo) { - VirtualDiskSparseVer1BackingInfo backingInfo = new VirtualDiskSparseVer1BackingInfo(); - backingInfo.setDiskMode(((VirtualDiskSparseVer1BackingInfo)parentBacking).getDiskMode()); - backingInfo.setDatastore(morDs); - backingInfo.setFileName(vmdkDatastorePath); - backingInfo.setParent((VirtualDiskSparseVer1BackingInfo)parentBacking); - disk.setBacking(backingInfo); - } else if(parentBacking instanceof VirtualDiskSparseVer2BackingInfo) { - VirtualDiskSparseVer2BackingInfo backingInfo = new VirtualDiskSparseVer2BackingInfo(); - backingInfo.setDiskMode(((VirtualDiskSparseVer2BackingInfo)parentBacking).getDiskMode()); - backingInfo.setDatastore(morDs); - backingInfo.setFileName(vmdkDatastorePath); - backingInfo.setParent((VirtualDiskSparseVer2BackingInfo)parentBacking); - disk.setBacking(backingInfo); - } else { - throw new Exception("Unsupported disk backing: " + parentBacking.getClass().getCanonicalName()); - } - - if(controllerKey < 0) - controllerKey = vmMo.getIDEDeviceControllerKey(); - disk.setControllerKey(controllerKey); - if(deviceNumber < 0) + + // vmdkDatastorePath: [datastore name] vmdkFilePath, create delta disk based on disk from template + public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePath, + int sizeInMb, ManagedObjectReference morDs, VirtualDisk templateDisk, int deviceNumber, int contextNumber) throws Exception { + + assert(templateDisk != null); + VirtualDeviceBackingInfo parentBacking = templateDisk.getBacking(); + assert(parentBacking != null); + + // TODO Not sure if we need to check if the disk in template and the new disk needs to share the + // same datastore + VirtualDisk disk = new VirtualDisk(); + if(parentBacking instanceof VirtualDiskFlatVer1BackingInfo) { + VirtualDiskFlatVer1BackingInfo backingInfo = new VirtualDiskFlatVer1BackingInfo(); + backingInfo.setDiskMode(((VirtualDiskFlatVer1BackingInfo)parentBacking).getDiskMode()); + backingInfo.setDatastore(morDs); + backingInfo.setFileName(vmdkDatastorePath); + backingInfo.setParent((VirtualDiskFlatVer1BackingInfo)parentBacking); + disk.setBacking(backingInfo); + } else if(parentBacking instanceof VirtualDiskFlatVer2BackingInfo) { + VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo(); + backingInfo.setDiskMode(((VirtualDiskFlatVer2BackingInfo)parentBacking).getDiskMode()); + backingInfo.setDatastore(morDs); + backingInfo.setFileName(vmdkDatastorePath); + backingInfo.setParent((VirtualDiskFlatVer2BackingInfo)parentBacking); + disk.setBacking(backingInfo); + } else if(parentBacking instanceof VirtualDiskRawDiskMappingVer1BackingInfo) { + VirtualDiskRawDiskMappingVer1BackingInfo backingInfo = new VirtualDiskRawDiskMappingVer1BackingInfo(); + backingInfo.setDiskMode(((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking).getDiskMode()); + backingInfo.setDatastore(morDs); + backingInfo.setFileName(vmdkDatastorePath); + backingInfo.setParent((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking); + disk.setBacking(backingInfo); + } else if(parentBacking instanceof VirtualDiskSparseVer1BackingInfo) { + VirtualDiskSparseVer1BackingInfo backingInfo = new VirtualDiskSparseVer1BackingInfo(); + backingInfo.setDiskMode(((VirtualDiskSparseVer1BackingInfo)parentBacking).getDiskMode()); + backingInfo.setDatastore(morDs); + backingInfo.setFileName(vmdkDatastorePath); + backingInfo.setParent((VirtualDiskSparseVer1BackingInfo)parentBacking); + disk.setBacking(backingInfo); + } else if(parentBacking instanceof VirtualDiskSparseVer2BackingInfo) { + VirtualDiskSparseVer2BackingInfo backingInfo = new VirtualDiskSparseVer2BackingInfo(); + backingInfo.setDiskMode(((VirtualDiskSparseVer2BackingInfo)parentBacking).getDiskMode()); + backingInfo.setDatastore(morDs); + backingInfo.setFileName(vmdkDatastorePath); + backingInfo.setParent((VirtualDiskSparseVer2BackingInfo)parentBacking); + disk.setBacking(backingInfo); + } else { + throw new Exception("Unsupported disk backing: " + parentBacking.getClass().getCanonicalName()); + } + + if(controllerKey < 0) + controllerKey = vmMo.getIDEDeviceControllerKey(); + disk.setControllerKey(controllerKey); + if(deviceNumber < 0) deviceNumber = vmMo.getNextDeviceNumber(controllerKey); disk.setKey(-contextNumber); @@ -227,6 +227,46 @@ public class VmwareHelper { setParentBackingInfo(backingInfo, morDs, parentDisks); } + disk.setBacking(backingInfo); + + if(controllerKey < 0) + controllerKey = vmMo.getIDEDeviceControllerKey(); + if(deviceNumber < 0) + deviceNumber = vmMo.getNextDeviceNumber(controllerKey); + + disk.setControllerKey(controllerKey); + disk.setKey(-contextNumber); + disk.setUnitNumber(deviceNumber); + + VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); + connectInfo.setConnected(true); + connectInfo.setStartConnected(true); + disk.setConnectable(connectInfo); + + return disk; + } + + public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, + Pair[] vmdkDatastorePathChain, + int deviceNumber, int contextNumber) throws Exception { + + assert(vmdkDatastorePathChain != null); + assert(vmdkDatastorePathChain.length >= 1); + + VirtualDisk disk = new VirtualDisk(); + + VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo(); + backingInfo.setDatastore(vmdkDatastorePathChain[0].second()); + backingInfo.setFileName(vmdkDatastorePathChain[0].first()); + backingInfo.setDiskMode(VirtualDiskMode.persistent.toString()); + if(vmdkDatastorePathChain.length > 1) { + Pair[] parentDisks = new Pair[vmdkDatastorePathChain.length - 1]; + for(int i = 0; i < vmdkDatastorePathChain.length - 1; i++) + parentDisks[i] = vmdkDatastorePathChain[i + 1]; + + setParentBackingInfo(backingInfo, parentDisks); + } + disk.setBacking(backingInfo); if(controllerKey < 0) @@ -245,32 +285,50 @@ public class VmwareHelper { return disk; } - + + private static void setParentBackingInfo(VirtualDiskFlatVer2BackingInfo backingInfo, + ManagedObjectReference morDs, String[] parentDatastorePathList) { + + VirtualDiskFlatVer2BackingInfo parentBacking = new VirtualDiskFlatVer2BackingInfo(); + parentBacking.setDatastore(morDs); + parentBacking.setDiskMode(VirtualDiskMode.persistent.toString()); + + if(parentDatastorePathList.length > 1) { + String[] nextDatastorePathList = new String[parentDatastorePathList.length -1]; + for(int i = 0; i < parentDatastorePathList.length -1; i++) + nextDatastorePathList[i] = parentDatastorePathList[i + 1]; + setParentBackingInfo(parentBacking, morDs, nextDatastorePathList); + } + parentBacking.setFileName(parentDatastorePathList[0]); + + backingInfo.setParent(parentBacking); + } + private static void setParentBackingInfo(VirtualDiskFlatVer2BackingInfo backingInfo, - ManagedObjectReference morDs, String[] parentDatastorePathList) { + Pair[] parentDatastorePathList) { VirtualDiskFlatVer2BackingInfo parentBacking = new VirtualDiskFlatVer2BackingInfo(); - parentBacking.setDatastore(morDs); + parentBacking.setDatastore(parentDatastorePathList[0].second()); parentBacking.setDiskMode(VirtualDiskMode.persistent.toString()); if(parentDatastorePathList.length > 1) { - String[] nextDatastorePathList = new String[parentDatastorePathList.length -1]; + Pair[] nextDatastorePathList = new Pair[parentDatastorePathList.length -1]; for(int i = 0; i < parentDatastorePathList.length -1; i++) nextDatastorePathList[i] = parentDatastorePathList[i + 1]; - setParentBackingInfo(parentBacking, morDs, nextDatastorePathList); + setParentBackingInfo(parentBacking, nextDatastorePathList); } - parentBacking.setFileName(parentDatastorePathList[0]); + parentBacking.setFileName(parentDatastorePathList[0].first()); backingInfo.setParent(parentBacking); } - - public static Pair prepareIsoDevice(VirtualMachineMO vmMo, String isoDatastorePath, ManagedObjectReference morDs, - boolean connect, boolean connectAtBoot, int deviceNumber, int contextNumber) throws Exception { - - boolean newCdRom = false; - VirtualCdrom cdRom = (VirtualCdrom )vmMo.getIsoDevice(); - if(cdRom == null) { - newCdRom = true; + + public static Pair prepareIsoDevice(VirtualMachineMO vmMo, String isoDatastorePath, ManagedObjectReference morDs, + boolean connect, boolean connectAtBoot, int deviceNumber, int contextNumber) throws Exception { + + boolean newCdRom = false; + VirtualCdrom cdRom = (VirtualCdrom )vmMo.getIsoDevice(); + if(cdRom == null) { + newCdRom = true; cdRom = new VirtualCdrom(); assert(vmMo.getIDEDeviceControllerKey() >= 0);