VMware 虚拟机增量备份时获取的 changid 为null
问题描述
VMware 虚拟机增量备份时,需要获取前一次备份所生成的 changeId,该 id 用于标记前一次备份截止的位置,下一次备份的起始位置,通过这个 changeId 可以查询出虚拟机自上次备份到当前时间点虚拟机有变化的数据块起始范围(changedAreas),用到的查询方法是 vim25.jar 包中的 VimPortType.queryChangedDiskAreas 方法,该接口方法定义如下:
public abstract DiskChangeInfo queryChangedDiskAreas(
@WebParam(name = "_this", targetNamespace = "urn:vim25") ManagedObjectReference paramManagedObjectReference1,
@WebParam(name = "snapshot", targetNamespace = "urn:vim25") ManagedObjectReference paramManagedObjectReference2,
@WebParam(name = "deviceKey", targetNamespace = "urn:vim25") int paramInt,
@WebParam(name = "startOffset", targetNamespace = "urn:vim25") long paramLong,
@WebParam(name = "changeId", targetNamespace = "urn:vim25") String paramString)
throws FileFaultFaultMsg, NotFoundFaultMsg, RuntimeFaultFaultMsg;
但获取的 changId 一直为 null,以为是虚拟机的这个值根本没设置,实在没辙后请教了老大,老大指出了问题所在,并让我通过查 MOB (Managed Object Browser,托管对象浏览器)查对象的属性值。
问题原因
虚拟机里面有两个地方有 changId ,一个是根据虚拟机属性路径(config.hardware.device[2000].backing)中找到的 changeId,该 changeId 为空,如下图为 Unset:
另一个是根据虚拟机快照下的属性路径中找到的 changeId,该 changeId 不为空,如下图:
而我调用 queryChangedDiskAreas 方法时,传入的参数为虚拟机的托管对象引用,所以造成获取的 changeId 为 null。
问题解决
将 queryChangedDiskAreas 方法的入参改为此次备份所生成的快照托管对象引用即可,下面为具体方法:
/**
* @Title: getChangeId
* @Description: 获得快照中对应虚拟磁盘的changeId
* @param vmMor 虚拟机托管对象引用
* @param vmName 虚拟机名称
* @param snapshotName 快照名称
* @throws RuntimeFaultFaultMsg
* @throws InvalidPropertyFaultMsg
* @author zxk
* @version 1.0
*/
public String getChangeId(ManagedObjectReference vmMor, String vmName, String snapshotName)
throws RuntimeFaultFaultMsg, InvalidPropertyFaultMsg {
String changeId = null;
// 获取快照托管对象引用
ManagedObjectReference snMor = getSnapshotReference(vmMor, vmName, snapshotName);
// 获取快照对应的虚拟设备
ArrayOfVirtualDevice devs = (ArrayOfVirtualDevice) getMOREFs.entityProps(snMor, new String[]{"config.hardware.device"}).get("config.hardware.device");
// 遍历虚拟设备以得到虚拟磁盘
for (VirtualDevice vd : devs.getVirtualDevice()) {
if (vd instanceof VirtualDisk) {
VirtualDisk disk = (VirtualDisk) vd;
VirtualDiskFlatVer2BackingInfo bi = (VirtualDiskFlatVer2BackingInfo) disk.getBacking();
changeId = bi.getChangeId();
}
}
return changeId;
}
获取快照托管对象引用的方法
private ManagedObjectReference getSnapshotReference(ManagedObjectReference vmmor, String vmName, String snapName)
throws RuntimeFaultFaultMsg, InvalidPropertyFaultMsg {
VirtualMachineSnapshotInfo snapInfo =
(VirtualMachineSnapshotInfo) getMOREFs.entityProps(vmmor, new String[] {"snapshot"}).get("snapshot");
ManagedObjectReference snapmor = null;
if (snapInfo != null) {
List<VirtualMachineSnapshotTree> listvmst = snapInfo.getRootSnapshotList();
snapmor = traverseSnapshotInTree(listvmst, snapName, false);
if (snapmor == null) {
System.out.println("No Snapshot named : " + snapName + " found for VirtualMachine : " + vmName);
}
} else {
System.out.println("No Snapshots found for VirtualMachine : " + vmName);
}
return snapmor;
}
总结 反思
这个问题是对虚拟机增量备份机制的细节理解的不够深入导致的,因为不知道 changeId 是由哪个对象生成,才会传入错误的对象参数;
其实,如果细心点的话,会发现 API 接口里有指明要传入的第二个参数为快照对象引用:
@WebParam(name = "snapshot", targetNamespace = "urn:vim25")ManagedObjectReference paramManagedObjectReference2
再加上一直没用过 MOB 这个查询对象属性的功能,出现问题时,无从获取问题出现的具体原因。