Add support routines for incremental snapshot support

This commit is contained in:
Kelven Yang 2012-05-11 17:17:48 -07:00
parent fa1bac5faf
commit 3020df75f1
4 changed files with 268 additions and 182 deletions

View File

@ -14,11 +14,13 @@ package com.cloud.hypervisor.vmware.mo;
import java.util.GregorianCalendar; 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.hypervisor.vmware.util.VmwareContext;
import com.cloud.serializer.GsonHelper; 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.google.gson.Gson;
import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.DynamicProperty;
import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.ManagedObjectReference;
@ -29,40 +31,6 @@ public class TestVmwareMO extends Log4jEnabledTestCase {
private static final Logger s_logger = Logger.getLogger(TestVmwareMO.class); private static final Logger s_logger = Logger.getLogger(TestVmwareMO.class);
public void test() { 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);
}
} }
} }

View File

@ -200,71 +200,98 @@ public class SnapshotDescriptor {
info.setDisks(disks); info.setDisks(disks);
info.setDisplayName(_properties.getProperty(String.format("snapshot%d.displayName", id))); info.setDisplayName(_properties.getProperty(String.format("snapshot%d.displayName", id)));
l.add(info); 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 { @Override
private String _diskFileName; public String toString() {
private String _deviceName; return "DiskInfo: { device: " + _deviceName + ", file: " + _diskFileName + " }";
}
public DiskInfo(String diskFileName, String deviceName) { }
_diskFileName = diskFileName; }
_deviceName = deviceName;
}
public String getDiskFileName() {
return _diskFileName;
}
public String getDeviceName() {
return _deviceName;
}
}
}

View File

@ -944,7 +944,40 @@ public class VirtualMachineMO extends BaseMO {
s_logger.trace("vCenter API trace - attachDisk() done(successfully)"); s_logger.trace("vCenter API trace - attachDisk() done(successfully)");
} }
// vmdkDatastorePath: [datastore name] vmdkFilePath public void attachDisk(Pair<String, ManagedObjectReference>[] 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<Pair<String, ManagedObjectReference>> detachDisk(String vmdkDatastorePath, boolean deleteBackingFile) throws Exception { public List<Pair<String, ManagedObjectReference>> detachDisk(String vmdkDatastorePath, boolean deleteBackingFile) throws Exception {
if(s_logger.isTraceEnabled()) if(s_logger.isTraceEnabled())

View File

@ -126,73 +126,73 @@ public class VmwareHelper {
if(deviceNumber < 0) if(deviceNumber < 0)
deviceNumber = vmMo.getNextDeviceNumber(controllerKey); deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
disk.setControllerKey(controllerKey); disk.setControllerKey(controllerKey);
disk.setKey(-contextNumber); disk.setKey(-contextNumber);
disk.setUnitNumber(deviceNumber); disk.setUnitNumber(deviceNumber);
disk.setCapacityInKB(sizeInMb*1024); disk.setCapacityInKB(sizeInMb*1024);
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setConnected(true); connectInfo.setConnected(true);
connectInfo.setStartConnected(true); connectInfo.setStartConnected(true);
disk.setConnectable(connectInfo); disk.setConnectable(connectInfo);
return disk; return disk;
} }
// vmdkDatastorePath: [datastore name] vmdkFilePath, create delta disk based on disk from template // vmdkDatastorePath: [datastore name] vmdkFilePath, create delta disk based on disk from template
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePath, public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePath,
int sizeInMb, ManagedObjectReference morDs, VirtualDisk templateDisk, int deviceNumber, int contextNumber) throws Exception { int sizeInMb, ManagedObjectReference morDs, VirtualDisk templateDisk, int deviceNumber, int contextNumber) throws Exception {
assert(templateDisk != null); assert(templateDisk != null);
VirtualDeviceBackingInfo parentBacking = templateDisk.getBacking(); VirtualDeviceBackingInfo parentBacking = templateDisk.getBacking();
assert(parentBacking != null); assert(parentBacking != null);
// TODO Not sure if we need to check if the disk in template and the new disk needs to share the // TODO Not sure if we need to check if the disk in template and the new disk needs to share the
// same datastore // same datastore
VirtualDisk disk = new VirtualDisk(); VirtualDisk disk = new VirtualDisk();
if(parentBacking instanceof VirtualDiskFlatVer1BackingInfo) { if(parentBacking instanceof VirtualDiskFlatVer1BackingInfo) {
VirtualDiskFlatVer1BackingInfo backingInfo = new VirtualDiskFlatVer1BackingInfo(); VirtualDiskFlatVer1BackingInfo backingInfo = new VirtualDiskFlatVer1BackingInfo();
backingInfo.setDiskMode(((VirtualDiskFlatVer1BackingInfo)parentBacking).getDiskMode()); backingInfo.setDiskMode(((VirtualDiskFlatVer1BackingInfo)parentBacking).getDiskMode());
backingInfo.setDatastore(morDs); backingInfo.setDatastore(morDs);
backingInfo.setFileName(vmdkDatastorePath); backingInfo.setFileName(vmdkDatastorePath);
backingInfo.setParent((VirtualDiskFlatVer1BackingInfo)parentBacking); backingInfo.setParent((VirtualDiskFlatVer1BackingInfo)parentBacking);
disk.setBacking(backingInfo); disk.setBacking(backingInfo);
} else if(parentBacking instanceof VirtualDiskFlatVer2BackingInfo) { } else if(parentBacking instanceof VirtualDiskFlatVer2BackingInfo) {
VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo(); VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo();
backingInfo.setDiskMode(((VirtualDiskFlatVer2BackingInfo)parentBacking).getDiskMode()); backingInfo.setDiskMode(((VirtualDiskFlatVer2BackingInfo)parentBacking).getDiskMode());
backingInfo.setDatastore(morDs); backingInfo.setDatastore(morDs);
backingInfo.setFileName(vmdkDatastorePath); backingInfo.setFileName(vmdkDatastorePath);
backingInfo.setParent((VirtualDiskFlatVer2BackingInfo)parentBacking); backingInfo.setParent((VirtualDiskFlatVer2BackingInfo)parentBacking);
disk.setBacking(backingInfo); disk.setBacking(backingInfo);
} else if(parentBacking instanceof VirtualDiskRawDiskMappingVer1BackingInfo) { } else if(parentBacking instanceof VirtualDiskRawDiskMappingVer1BackingInfo) {
VirtualDiskRawDiskMappingVer1BackingInfo backingInfo = new VirtualDiskRawDiskMappingVer1BackingInfo(); VirtualDiskRawDiskMappingVer1BackingInfo backingInfo = new VirtualDiskRawDiskMappingVer1BackingInfo();
backingInfo.setDiskMode(((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking).getDiskMode()); backingInfo.setDiskMode(((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking).getDiskMode());
backingInfo.setDatastore(morDs); backingInfo.setDatastore(morDs);
backingInfo.setFileName(vmdkDatastorePath); backingInfo.setFileName(vmdkDatastorePath);
backingInfo.setParent((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking); backingInfo.setParent((VirtualDiskRawDiskMappingVer1BackingInfo)parentBacking);
disk.setBacking(backingInfo); disk.setBacking(backingInfo);
} else if(parentBacking instanceof VirtualDiskSparseVer1BackingInfo) { } else if(parentBacking instanceof VirtualDiskSparseVer1BackingInfo) {
VirtualDiskSparseVer1BackingInfo backingInfo = new VirtualDiskSparseVer1BackingInfo(); VirtualDiskSparseVer1BackingInfo backingInfo = new VirtualDiskSparseVer1BackingInfo();
backingInfo.setDiskMode(((VirtualDiskSparseVer1BackingInfo)parentBacking).getDiskMode()); backingInfo.setDiskMode(((VirtualDiskSparseVer1BackingInfo)parentBacking).getDiskMode());
backingInfo.setDatastore(morDs); backingInfo.setDatastore(morDs);
backingInfo.setFileName(vmdkDatastorePath); backingInfo.setFileName(vmdkDatastorePath);
backingInfo.setParent((VirtualDiskSparseVer1BackingInfo)parentBacking); backingInfo.setParent((VirtualDiskSparseVer1BackingInfo)parentBacking);
disk.setBacking(backingInfo); disk.setBacking(backingInfo);
} else if(parentBacking instanceof VirtualDiskSparseVer2BackingInfo) { } else if(parentBacking instanceof VirtualDiskSparseVer2BackingInfo) {
VirtualDiskSparseVer2BackingInfo backingInfo = new VirtualDiskSparseVer2BackingInfo(); VirtualDiskSparseVer2BackingInfo backingInfo = new VirtualDiskSparseVer2BackingInfo();
backingInfo.setDiskMode(((VirtualDiskSparseVer2BackingInfo)parentBacking).getDiskMode()); backingInfo.setDiskMode(((VirtualDiskSparseVer2BackingInfo)parentBacking).getDiskMode());
backingInfo.setDatastore(morDs); backingInfo.setDatastore(morDs);
backingInfo.setFileName(vmdkDatastorePath); backingInfo.setFileName(vmdkDatastorePath);
backingInfo.setParent((VirtualDiskSparseVer2BackingInfo)parentBacking); backingInfo.setParent((VirtualDiskSparseVer2BackingInfo)parentBacking);
disk.setBacking(backingInfo); disk.setBacking(backingInfo);
} else { } else {
throw new Exception("Unsupported disk backing: " + parentBacking.getClass().getCanonicalName()); throw new Exception("Unsupported disk backing: " + parentBacking.getClass().getCanonicalName());
} }
if(controllerKey < 0) if(controllerKey < 0)
controllerKey = vmMo.getIDEDeviceControllerKey(); controllerKey = vmMo.getIDEDeviceControllerKey();
disk.setControllerKey(controllerKey); disk.setControllerKey(controllerKey);
if(deviceNumber < 0) if(deviceNumber < 0)
deviceNumber = vmMo.getNextDeviceNumber(controllerKey); deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
disk.setKey(-contextNumber); disk.setKey(-contextNumber);
@ -227,6 +227,46 @@ public class VmwareHelper {
setParentBackingInfo(backingInfo, morDs, parentDisks); 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<String, ManagedObjectReference>[] 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<String, ManagedObjectReference>[] 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); disk.setBacking(backingInfo);
if(controllerKey < 0) if(controllerKey < 0)
@ -245,32 +285,50 @@ public class VmwareHelper {
return disk; 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, private static void setParentBackingInfo(VirtualDiskFlatVer2BackingInfo backingInfo,
ManagedObjectReference morDs, String[] parentDatastorePathList) { Pair<String, ManagedObjectReference>[] parentDatastorePathList) {
VirtualDiskFlatVer2BackingInfo parentBacking = new VirtualDiskFlatVer2BackingInfo(); VirtualDiskFlatVer2BackingInfo parentBacking = new VirtualDiskFlatVer2BackingInfo();
parentBacking.setDatastore(morDs); parentBacking.setDatastore(parentDatastorePathList[0].second());
parentBacking.setDiskMode(VirtualDiskMode.persistent.toString()); parentBacking.setDiskMode(VirtualDiskMode.persistent.toString());
if(parentDatastorePathList.length > 1) { if(parentDatastorePathList.length > 1) {
String[] nextDatastorePathList = new String[parentDatastorePathList.length -1]; Pair<String, ManagedObjectReference>[] nextDatastorePathList = new Pair[parentDatastorePathList.length -1];
for(int i = 0; i < parentDatastorePathList.length -1; i++) for(int i = 0; i < parentDatastorePathList.length -1; i++)
nextDatastorePathList[i] = parentDatastorePathList[i + 1]; nextDatastorePathList[i] = parentDatastorePathList[i + 1];
setParentBackingInfo(parentBacking, morDs, nextDatastorePathList); setParentBackingInfo(parentBacking, nextDatastorePathList);
} }
parentBacking.setFileName(parentDatastorePathList[0]); parentBacking.setFileName(parentDatastorePathList[0].first());
backingInfo.setParent(parentBacking); backingInfo.setParent(parentBacking);
} }
public static Pair<VirtualDevice, Boolean> prepareIsoDevice(VirtualMachineMO vmMo, String isoDatastorePath, ManagedObjectReference morDs, public static Pair<VirtualDevice, Boolean> prepareIsoDevice(VirtualMachineMO vmMo, String isoDatastorePath, ManagedObjectReference morDs,
boolean connect, boolean connectAtBoot, int deviceNumber, int contextNumber) throws Exception { boolean connect, boolean connectAtBoot, int deviceNumber, int contextNumber) throws Exception {
boolean newCdRom = false; boolean newCdRom = false;
VirtualCdrom cdRom = (VirtualCdrom )vmMo.getIsoDevice(); VirtualCdrom cdRom = (VirtualCdrom )vmMo.getIsoDevice();
if(cdRom == null) { if(cdRom == null) {
newCdRom = true; newCdRom = true;
cdRom = new VirtualCdrom(); cdRom = new VirtualCdrom();
assert(vmMo.getIDEDeviceControllerKey() >= 0); assert(vmMo.getIDEDeviceControllerKey() >= 0);