5 虚拟磁盘接口示例代码

编译示例程序

这些程序代码是用C++编写的,但是虚拟磁盘接口同样支持C。如果要编译通过,还需要正确的DLL和共享对象。你可以用多种方式保证正确的动态加载。

  • VDDK程序中设置路径。

  • 使用LinuxWindows Visual Studio设置shell路径。默认安装的话,Linux路径是/usr/share/doc/vmware-vix-disklib/sample

  • Windows系统变量中设置路径。在XP系统上,右键“我的电脑 > 属性 > 高级 > 环境变量”,在“系统变量”下拉列表中选择“Path”并点击“编辑”,加入VDDK的二进制库的路径。在Windows7系统上,右键“我的电脑 > 属性 > 高级系统设置 > 环境变量”,在“系统变量”列表中选择“Path”,点击“编辑”,加入VDDK二进制库的路径。

需要注意的是,VDDK使用相对路径加载DLL文件,而不是使用绝对路径,所有DLL的不同版本可能造成冲突问题。

Windows上的Visual C++

要编译程序,需要在下面这个位置找到vixDiskLibSample.cpp文件:

C:\ProgramFiles\VMware\VMware Virtual Disk Development Kit\doc\sample\

对于VDDK5.5及以后的版本,需要保证Visual Studio安装了64位的编译工具。双击vcproj文件,可能会转换新版本的格式,然后选择“编译 > 编译解决方案”。

要运行编译后的程序,选择“调试 > 开始运行”,或者在命令行中定位到上面给出的doc\sample目录,输入:

Debug\vixdisklibsample.exe

SLNVCPROJ文件

VisualStudio的解决方案文件vixDiskLibSample.sln和工程文件vixDiskLibSample.vcproj文件都包含在示例目录中。

Linux系统上的C++

在下面的目录中找到源程序代码:

  /usr/share/doc/vmware-vix-disklib/samples/disklib

你可以将vixDiskLibSample.cpp和它的Makefile文件拷贝任何具有写权限的目录。在一些Linux系统上,你还需要在第15行的#else后面通过#include包含头文件。使用make命令编译,然后运行程序:

make

./vix-disklib-sample

注意:如果失败的话,编辑/etc/ld.so.conf文件然后使用root权限运行ldconfig命令,或者编辑你的LD_LIBRARY_PATH环境变量包含库安装目录,/usr/lib/vmware-vix-disklib/lib64

Makefile

Makefile会提取任何编译需要但是没有安装的包。

需要的库文件

Linux系统上,虚拟磁盘库和动态库或者共享对象是在一起的,简化了第三方以及开源组件的发行。

Windows的链接需要lib/vixDiskLib.lib文件,运行时需要bin/*.dll文件。

Linux在链接和运行时均使用.so文件。

用法介绍

不使用参数运行示例程序会得到如下输出信息:

使用方法:vixdisklibsamplecommand [options] diskPath

命令:

-create:创建由-cap指定的容量大小的稀疏虚拟磁盘。

-redoparentPath:针对基准磁盘“parentPath”创建一个重写日志“diskPath”。

-info:显示指定虚拟磁盘的信息。

-dump:以十六进制的方式显示指定范围内的扇区内容。

-fill:使用-val指定的值填充指定范围内的磁盘扇区。

-wmetakey value:将键值对写入磁盘的元数据中。

-rmetakey:显示指定的元数据键的值。

-meta:显示所有的磁盘元数据项。

-clonesourcePath:克隆源VMDK,通常是克隆到远程主机。

-readbenchblocksize:以扇区为单位,使用指定的块大小,在磁盘上读取标签(do read benchmark ona disk using the specified I/O block size in sectors)

-writebenchblocksize:以扇区为单位,使用指定的I/O块大小,在磁盘上写入标签(do write benchmark on disk usingthe specified I/O block size in sectors)

选项:

-adapter[ide|scsi]:“创建”命令时使用的总线类型选项,默认是“SCSI”。

-startndumpfill命令时使用的开始扇区,默认为0

-countndumpfill命令时使用的扇区个数,默认为1

-valbytefill命令中用于填充的字节值。

-capmegabytescreate命令使用的容量大小,MB为单位,默认是100

-single:作为单个磁盘打开一个文件,默认打开整个磁盘链。

-multithreadn:开启n个线程,并将文件拷贝到n个新文件。

-hosthostname:主机名称或IP地址

-useruserid:主机的用户名,默认是root

-passwordpassword:主机密码

-portport:用于连接主机的端口,默认是902

-vmvmPath=/path/to/vm:包含虚拟磁盘的虚拟机路径。

-libdirdir:包含vixDiskLIbPlugin库的目录。

-initexconfigfile:用来调用VixDiskLib_InitEx()

-ssmorefmoref:虚拟机快照的托管对象引用。

-modemode:传递给VixDiskLib_ConnectEx的模式字符串。

-thumbstirng:用于验证的SLL指纹字符串。

-thumb选项是在VDDK5.1版中才有的安全相关的特性。

示例程序中的-single选项,打开单个链接而不是整个磁盘链,支持本地磁盘,不支持远程托管磁盘。

要使用示例程序连接到ESXi主机,需要指定-host-user-password选项,并提供ESXi主机上datastore中的diskPath。例如:

vix-disklib-sample–info –host esxS –user root –password secret “[datastore1]/.vmdk”

如果要连接到vCenter服务器,还需要指定-libdir-vm选项。程序需要libdirDiskLibPlugin能够连接到vCenter服务器,它被用来定位VM(Programs need libdir so theDiskLibPlugin can connect with vCenter Server, which must locate the VM)。例如:

vix-disklib-sample–info –host vcS –user Administrator –password secret –libdir -vm vmPath= “[] /.vmdk”

vmPathvShpere客户端中制定,从vCenter开始,并在VM名称前插入/vm/。通过点击“编辑设置 > 硬盘”并拷贝“磁盘文件”名称可得到diskPath

vix-disklib-sample–info –host vcS –user Administrator –password secret –libdir/user/lib/vmware-vix-disklib/lib64 –vm vmPath=Datacenter/vm/RHELS “[datastore]RHELS/RHELS.vmdk”

要使用高级传输进行连接,例如连接到SAN存储上虚拟机磁盘,必须指定-mode-ssmoref选项。VixDiskLib_ConnectEx()需要传输模式和快照的托管对象引用。要找到ssmoref,登陆到vCenter服务器的托管对象浏览,点击“内容(content) > 根目录(rootFolder) > 数据中心(Datacenter) > 数据存储(datastore) > 虚拟机(vm) > 快照(snapshot)”。快照必须存在,因为打开正在运行的虚拟机的基准磁盘是相当危险的。

vix-disklib-smaple–info –host vcS –user Administrator –password secret –mode san –libdir/usr/lib/vmware-vix-disklib/lib64 –vm vmPath=Datacenter/vm RHELS –ssmorefsnapshort-72 “[datastore] RHELS/RHELS.vmdk”

Windows上,VDDKdiskLibPlugin.dll安装在\bin文件夹,而不是\lib文件夹,所以需要相应的修改

遍历示例代码

WindowsLinux的示例代码都是一样的,Win32代码会使用#ifdef块。

包含文件

Windows的动态链接库(DLL)声明在process.h中,而Linux的共享对象(.so)声明在dlfcn.h中。Windows提供了tchar.h文件来扩展Unicode字符文本,在Linux中不可用。

定义和结构体

示例代码使用了12个二进制位移操作(1 << 11)来标识可用的命令和多线程选项。虚拟磁盘库差不多有30个函数,一些用来初始化和清理操作。下面函数在示例程序没有用到:

VixDiskLib_Rename()

VixDiskLib_Defragment()

VixDiskLib_Grow()

VixDiskLib_Shrink()

VixDiskLib_Unlink()

VixDiskLib_Attach()

示例代码通过appGlobals结构体传递状态信息。

动态加载

#ifdefDYNAMIC_LOADING块很长,从97行开始,到339行结束,包含动态加载需要的函数定义,还包含LoadOneFunc()函数,用来从动态库中获得任意请求的函数,并使用DynLoadDiskLib()过程来绑定它。这个过程可以称为“运行时加载(runtime loading)”,以区别动态链接。

如果要长水Linux系统上运行时加载,在Makefile文件的g++后面加上-DDYNAMIC_LOADING并重新编译。Windows上,在工程中定义DYNAMIC_LOADING

封装类

动态加载块后面是两个封装类,一个用于错误码和描述文字,另一个用来管理磁盘的链接句柄。

错误封装出现在“catch”和“throw”语句中,简化了函数中的错误处理。VixDisk封装类提供了打开和关闭磁盘连接的有效方式。除了在动态加载中,库函数VixDiskLib_Open()VixDiskLib_Close()唯一出现的其他地方,是在程序结束附近的CopyThread()函数中。

命令函数(Command Functions)

接着出现的是print_usage消息,输出如“用法介绍”一节描述的一样的内容。

接下来是 main()函数,它设置默认的操作和选项,并解析命令行参数,取代默认的操作或选项,以及执行定义的动态加载。定义的VixDiskLibConnectParams结构在初始状态全部被置为0

    VixDiskLibConnectParams cnxParams = {0};

要连接到ESX/ESXi主机,需要通过命令行参数-user-password传入正确的用户名和密码。还需要通过-host指定ESX/ESXi主机的名称,以及通过-vm参数传递库路径(vmxSpec)。这些值将会填充cnxParams结构。必须初始化所有的参数,特别是vmxSpec,否则连接将会出现异常。

调用VixDiskLib_Init()函数初始化库。在一个产品应用中,你可以指定logwarnpanic函数作为参数,而不使用默认的NULL

调用VixDiskLib_Connect()创建到磁盘的连接。如果没有使用-host参数,cnxParams.serverName就会为nulll,那么将会建立到本地主机上的本地磁盘之间的连接,否则将会连接到远程主机上的托管磁盘。使用-ssmoref参数,将会使用高级传输。

接下来,将会调用适当的函数完成请求的操作,如果出错将会显示错误信息。最后,main()函数将会关闭磁盘连接并退出。

DoInfo()

这个函数调用VixDiskLib_GetInfo()获取虚拟磁盘的相关信息,显示结果,然后调用VixDiskLib_freeInfo()释放内存。disk.Handle()参数来自VixDisk封装类。

在这个例子中,程序连接到叫“esx5”的ESX/ESXi主机,然后显示“Red Hat Enterprise Linux”客户机虚拟磁盘的信息,磁盘路径通常由“[datastore]”跟上虚拟机名称、VMDK文件名称组成。

vix-disklib-sample–info –host esx5 –user root –password secret “[datastore1] RHEL6/RHEL6.vmdk”

Disk“[datastore1] RHEL6/RHEL6.vmdk” is open using transport mode “nbd”.

capacity= 4194384 sectors

nmberof links = 1

adaptertype = LisLogic SCSI

BIOSgeometry = 0/0/0

physicalgeometry = 261/255/63

Transportmodes supported by vixDiskLib: file:nbdssl;nbd

如果将物理磁盘参数相乘,即261柱面 * 255磁头每柱面 * 63扇区每磁头,得到的结果是4192965,而第一行显示的容量是4194384。这个小的差异是由于对齐造成的。通常你至少会得到你所要求的容量。磁盘链接数表示磁盘链(重写日志,redo logs)中从原始的父磁盘开始的子磁盘个数,最少为1。父磁盘有一个链接,它的子磁盘有两个,子磁盘的子磁盘有三个,以此类推。

DoCreate()

这个函数调用VixDiskLib_Create()创建一个虚拟磁盘。适配类型默认是SCSI,可以通过命令行指定为IDE类型。大小默认为100M,可以通过-cap指定容量。因为扇区大小是512字节,apppGlobals.mbsize应该乘以2028而不是1024。类型总是单片稀疏型,硬件类型是Workstation 5。在产品应用中,可以定义progressFunc以及回调数据,而不使用NULL。输入下面的命令创建一个简单的VMDK文件(第一行只用于Linux系统)

exportLD_LIBRARY_PATH = /usr/lib/vmware-vix-disklib/lib64

vix-disklib-sample–create sample.vmdk

单片稀疏型的VMDK文件初始大小是65535字节(2^16)。当第一次写入这种类型的虚拟磁盘时,正如下面的DoFill()那样,VMDK扩展到131075字节(2^17),保存了比需要的更多的空间。你可以通过-dump选项验证文件内容。

DoRedo()

这个命令调用VixDiskLib_CreateChild()来创建一个重写日志。子磁盘记录父磁盘或前一个子磁盘发生改变的磁盘扇区。多个子磁盘可以链接成一系列的重写日志。

示例程序没有演示如何使用VxiDiskLib_Attach(),通过它可以访问磁盘链中的一个链接。VixDiskLib_CreateChild()建立一个重写日志,使针对父磁盘的读写操作由子磁盘代替。提供一个磁盘链,VixDiskLib_Attach()创建一个相关的子磁盘,并链接到磁盘链中。

4-2演示了附加(attach)操作。

Write by DoFill()

这个函数调用VixDiskLib_Write()接口填充磁盘扇区,默认的填充值是1(字节值是FF),你还可以在命令行中通过-val指定值。默认情况下值填充磁盘的第一个扇区,但是可以通过使用-start-count参数来手动指定。

DoReadmetadata()

这个函数通过调用VixDiskLib_ReadMetadata()实现-rmeta命令行操作。例如,使用下面这个命令来获得全局唯一标示符:

vix-disklib-smaple–rmeta uuid sample.vmdk

DoWriteMetadata()

这个函数调用VixDiskLib_WriteMetadata()来实现-wmeta命令行操作。例如,使用下面这个命令来修改工具的版本:

vix-disklib-smaple–wmeta toolsversion 2 sample.vmdk

DoDumpMetadata()

这个函数使用VixDiskLib_GetMetadataKeys()VixDiskLib_ReadMetadata()函数完成-meta命令行选项。对每一个键值都需要调用两次读操作:一个用来判断值字符串的长度,另一个用来读取值字符串。

在下面的例子中,程序连接到名称为esx3ESX/ESXi主机,并显示一个Red Hat Enterprise Linux客户端的虚拟机的元数据,以及虚拟机的名称和VMDK文件名称:

vix-disklib-sampl–meta –host esx3 –user admin –password secret “[storage1] RHELS/RHELS.vmdk”

geometry.sectors= 63

geometry.heads= 255

geometry.cylinders= 522

datapterType= buslogic

toolsVersion= 1

virtualHwVersion= 7

工具版本和虚拟硬件版本出现在元数据中,而不是在磁盘信息中。几何信息(Geometry)和适配器类型重复重现,但是格式不同。其他一些没有列出来的元数据可能也会存在。

DoDump()

这个函数调用VixDiskLib_Read()函数来读取磁盘扇区,并以十六进制的形式显示扇区内容。默认情况只读取从0开始的第一个扇区,但是可以通过-start-count选项来指定开始位置和扇区个数。下面是一系列的演示命令:

vix-disklib-sample–createsample.vmdk

vix-disklib-sample–fill–val 1 sample.vmdk

vix-disklib-sample–fill–val 2 –start 1 –count 1 sample.vmdk

vix-disklib-sample–dump –start 0 –count 2 sample.vmdk

od–c sample.vmd

DoTestMultiThread()

这个函数使用Windows的多线程库,创建虚拟磁盘文件的多个拷贝。通过-multithreard命令行选项来指定拷贝的个数。示例程序针对每一个拷贝调用一次CopyThread()函数,它们都会按顺序调用6个虚拟磁盘API函数。

Linux上没有实现多线程选项。

DoClone()

这个函数调用VixDiskLib_Clone()来拷贝虚拟磁盘上的数据。通过第6个参数指定一个回调函数,显示克隆过程完成的进度信息。对于一个本地磁盘,默认的适配器类型是SCSI,除非通过命令行指定为IDE类型,大小为200M,也可以通过-cap选项指定大小,类型是单片稀疏的(monolithic sparse),平台是工作站5。对于ESX/ESXi主机,适配器类型由托管磁盘的类型决定,使用VixDiskLib_Connect()建立的连接参数。

最后一个参数如果TRUE,表示如果目标VDDK文件存在,则覆盖它。

克隆选项是一个良好的备份方法。通常克隆过的磁盘都很小,因为它可以更有效的组织。甚至一个完全分配的平面文件可以转换为稀疏文件。

SSL认证指纹(Certificate Thumbprint)

VDDK5.1发布的示例程序中,加入了-thumb选项,允许提供并使用SLL认证指纹。这个指纹被用来在vCenter服务器间进行认证。