5 虚拟磁盘接口示例代码
编译示例程序
这些程序代码是用C++编写的,但是虚拟磁盘接口同样支持C。如果要编译通过,还需要正确的DLL和共享对象。你可以用多种方式保证正确的动态加载。
在VDDK程序中设置路径。
使用Linux或Windows 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
SLN和VCPROJ文件
VisualStudio的解决方案文件vixDiskLibSample.sln和工程文件vixDiskLibSample.vcproj文件都包含在示例目录中。
Linux系统上的C++
在下面的目录中找到源程序代码:
/usr/share/doc/vmware-vix-disklib/samples/disklib
你可以将vixDiskLibSample.cpp和它的Makefile文件拷贝任何具有写权限的目录。在一些Linux系统上,你还需要在第15行的#else后面通过#include包含
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”。
-startn:dump、fill命令时使用的开始扇区,默认为0。
-countn:dump、fill命令时使用的扇区个数,默认为1。
-valbyte:fill命令中用于填充的字节值。
-capmegabytes:create命令使用的容量大小,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]
如果要连接到vCenter服务器,还需要指定-libdir和-vm选项。程序需要libdir,DiskLibPlugin能够连接到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
vmPath在vShpere客户端中制定,从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上,VDDK将diskLibPlugin.dll安装在\bin文件夹,而不是\lib文件夹,所以需要相应的修改
遍历示例代码
Windows和Linux的示例代码都是一样的,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()函数初始化库。在一个产品应用中,你可以指定log,warn,panic函数作为参数,而不使用默认的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命令行选项。对每一个键值都需要调用两次读操作:一个用来判断值字符串的长度,另一个用来读取值字符串。
在下面的例子中,程序连接到名称为esx3的ESX/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服务器间进行认证。