2018年12月5日水曜日

VDDK API を使って VDDK の操作をしてみた (コーディング編)

概要

前回はサンプルをコンパイルして実行してみました
今回はサンプルコードのように自分で VDDK API を使ったアプリを作成して動かしてみました
なるべくわかりやすいようにシンプルに作っています

全体を通して API Reference はこれが参考になると思います
が上記も情報がかなり少ないので頑張ってググるか Code の VMware Community を見たりすると解決できるかもしれません (が、基本は情報が少ないのでサンプルと格闘する時間が長くなると思います)

環境

  • CentOS 7
  • VCSA 6.5.0 9451637
  • VDDK API 6.7.1

サンプルコード全体

今回のサンプルは vmdk の情報を取得するサンプルになります
ほぼ同じ手順で別の API もコールできます

  • mkdir -p vmware-vix-disklib-distrib/doc/samples/firstLib
  • cd vmware-vix-disklib-distrib/doc/samples/firstLib
  • vim firstLib.cpp
#include <iostream>
#include "vixDiskLib.h"
using std::cout;
using std::endl;

#define VIXDISKLIB_VERSION_MAJOR 6
#define VIXDISKLIB_VERSION_MINOR 7

static struct {
  VixDiskLibConnection connection;
  char *libdir;
  char *cfgFile;
} params;

int main() {
  VixError err;

  err = VixDiskLib_InitEx(VIXDISKLIB_VERSION_MAJOR, VIXDISKLIB_VERSION_MINOR, NULL, NULL, NULL, params.libdir, params.cfgFile);
  printf("%lu\n", err);

  VixDiskLibConnectParams cnxParams = {0};
  cnxParams.vmxSpec = {(char*)"moref=vm-10"};
  cnxParams.specType = VIXDISKLIB_SPEC_VMX;
  cnxParams.serverName = {(char*)"192.168.100.20"};
  cnxParams.credType = VIXDISKLIB_CRED_UID;
  cnxParams.creds.uid.userName = {(char*)"administrator@vsphere.local"};
  cnxParams.creds.uid.password = {(char*)"xxxxxxxx"};
  cnxParams.thumbPrint = {(char*)"96:09:d6:5b:e0:83:58:1b:ba:2b:cc:78:22:88:33:36:64:50:32:eb"};
  err = VixDiskLib_ConnectEx(&cnxParams, 1, NULL, "nbd", &params.connection);
  printf("%lu\n", err);

  VixDiskLibHandle _handle = NULL;
  err = VixDiskLib_Open(params.connection, "[datastore1] vm01/vm01.vmdk", VIXDISKLIB_FLAG_OPEN_READ_ONLY, &_handle);
  printf("%lu\n", err);

  VixDiskLibInfo *info = NULL;
  err = VixDiskLib_GetInfo(_handle, &info);
  printf("%lu\n", err);

  cout << "capacity          = " << info->capacity << " sectors" << endl;
  cout << "number of links   = " << info->numLinks << endl;
  cout << "adapter type      = ";
  switch (info->adapterType) {
  case VIXDISKLIB_ADAPTER_IDE:
     cout << "IDE" << endl;
     break;
  case VIXDISKLIB_ADAPTER_SCSI_BUSLOGIC:
     cout << "BusLogic SCSI" << endl;
     break;
  case VIXDISKLIB_ADAPTER_SCSI_LSILOGIC:
     cout << "LsiLogic SCSI" << endl;
     break;
  default:
     cout << "unknown" << endl;
     break;
  }
  cout << "BIOS geometry     = " << info->biosGeo.cylinders <<
     "/" << info->biosGeo.heads << "/" << info->biosGeo.sectors << endl;
  cout << "physical geometry = " << info->physGeo.cylinders <<
     "/" << info->physGeo.heads << "/" << info->physGeo.sectors << endl;
  VixDiskLib_FreeInfo(info);
  cout << "Transport modes supported by vixDiskLib: " <<
     VixDiskLib_ListTransportModes() << endl;

  VixDiskLib_Disconnect(params.connection);
  return 0;
}

以下で細かく開設します

解説

最終的に vmdk から情報を取得するための API は VixDiskLib_GetInfo になります
これをコールするために必ず通る道があります

  • VixDiskLib_InitEx
  • VixDiskLib_ConnectEx
  • VixDiskLib_Open

を順番に実行します
また最後に VixDiskLib_Disconnect を実行します

VixDiskLib_InitEx

まず VixDiskLib_InitEx です
以下のように呼び出しています

err = VixDiskLib_InitEx(VIXDISKLIB_VERSION_MAJOR, VIXDISKLIB_VERSION_MINOR, NULL, NULL, NULL, params.libdir, params.cfgFile);`

VIXDISKLIB_VERSION_MAJORVIXDISKLIB_VERSION_MINOR はマクロとしてコード内で定義します
VDDK API のバージョンを管理するだけなので今回は 6.7 なので「6」「7」を格納します
次から 3 つの引数 NULL ですがこれはログ出力用のコールバックメソッドを指定することができます
ここでは紹介しませんが VDDK API 側の実行ログを細かくみたい場合は指定してください
次の 2 つの params.libdirparams.cfgFile はオプショナルなので今回は何も指定していません
定義自体は struct でコードの先頭で行っています

VixDiskLib_ConnectEx

次に VixDiskLib_ConnectEx です
これは vCenter に対しての接続を確立するための API です

VixDiskLibConnectParams cnxParams = {0};
cnxParams.serverName = {(char*)"192.168.100.20"};
cnxParams.credType = VIXDISKLIB_CRED_UID;
cnxParams.creds.uid.userName = {(char*)"administrator@vsphere.local"};
cnxParams.creds.uid.password = {(char*)"xxxxxxxx"};
cnxParams.thumbPrint = {(char*)"96:09:d6:5b:e0:83:58:1b:ba:2b:cc:78:22:88:33:36:64:50:32:eb"};
cnxParams.vmxSpec = {(char*)"moref=vm-10"};
cnxParams.specType = VIXDISKLIB_SPEC_VMX;
err = VixDiskLib_ConnectEx(&cnxParams, 1, NULL, "nbd", &params.connection);

認証情報などは VixDiskLibConnectParams クラスの変数に格納していきます
上記の場合は ID/PW による認証ですが session を使った認証もあるので詳しくはリファレンスを見てください
上記で設定しているのではすべて必須になります
serverName は vCenter の IP アドレスを設定します
credType は ID/PW 認証の場合 VIXDISKLIB_CRED_UID を指定します
VIXDISKLIB_CRED_UID は VDDK API 側に定義されているマクロです
creds.uid.userName は vCenter にアクセスするユーザを指定します
creds.uid.password は vCenter にアクセスするユーザのパスワードを指定します
thumbPrint は SSL 証明書を使っていない場合に必要になります
ブラウザなどで確認できるので各自の vCenter にアクセスしてそれを入力してください
ここまでが認証情報です

あとの vmxSpecspecType はアクセスする vmdk の主である VM を指定します
vmxSpec は少し特殊な方法で指定します
vCenter からみたときの対象の VM の MoRef (Managed Object Reference) ID を指定します
ポイントは vCenter から見たときの MoRef という点で ESXi から見たときと値が異なります
vm- で始まる MoRef を指定しましょう
また当然ですが取得したい vmdk の主とは異なる VM の MoRef を指定してもエラーになるので注意してください

あとの引数 1, NULL, "nbd", &params.connection はそれぞれ ReadOnly かどうか (1 の場合は ReadOnly)、スナップショット ID、アクセスモード、コネクションになります

成功すると params.connection が使えるようになります

VixDiskLib_Open

3 つ目の VixDiskLib_Open は対象のディスクにアクセスするための API です
ここで対象の vmdk があるパスを指定します

VixDiskLibHandle _handle = NULL;
err = VixDiskLib_Open(params.connection, "[datastore1] vm01/vm01.vmdk", VIXDISKLIB_FLAG_OPEN_READ_ONLY, &_handle);

先程設定された params.connection を使ってアクセスします
2 つ目の引数が vmdk のパスになります
フォーマットは Web Cilent でストレージのファイルブラウザで見たときのパスをそのまま入力します
VIXDISKLIB_FLAG_OPEN_READ_ONLY は ReadOnly かどうかのフラグになります
そして最後の _handle は vmdk にアクセスするためのハンドラになります
情報を取得する際にはこのハンドラを使ってアクセスします

先程の params.connection と同じで成功すると _handle が使えるようになります

VixDiskLib_GetInfo

そして最後の VixDiskLib_GetInfo で情報を取得します
成功すると VixDiskLibInfo の変数にいろいろと情報が格納されます

VixDiskLibInfo *info = NULL;
err = VixDiskLib_GetInfo(_handle, &info);

このあとのコードで cout, endl で囲まれたコードがたくさん出てきますがこれは info の情報を標準出力に出すためのコードです
サンプルにあったものをそのまま使っているのでここは好きなように編集してもらって大丈夫です

そして出力後に VixDiskLib_FreeInfo をコールしていますがこれは情報を取得するときに使用したメモリを開放するためにコールします
メモリリークの発生を抑えるためにコールします

コンパイルする

コンパイルする場所は VDDK のサンプルがあるパスで行います
そこじゃなくてもいいですが Makefile もありそれをそのまま流用できるので使うと楽です

  • cd vmware-vix-disklib-distrib/doc/samples/firstLib
  • vim Makefile
INCLUDEDIR=../../../include
LIBDIR=../../../lib64
LIBS=-ldl -lz -lsqlite3 -lcurl -lssl -lcrypto

ifdef VIX_AIO_BUFPOOL_SIZE
CXXFLAGS+= -DVIX_AIO_BUFPOOL_SIZE=$(VIX_AIO_BUFPOOL_SIZE)
endif

GCC_MAJOR_VER_GTEQ_4_8 := $(shell expr `$(CXX) -dumpversion | cut -f1,2 -d.` \>= 4.8)

ifeq "$(GCC_MAJOR_VER_GTEQ_4_8)" "1"
# this version support C++11
CXXFLAGS+= -std=c++11 -lpthread
else
# use boost libs
CXXFLAGS+= -lboost_system-gcc41-mt-1_42 -lboost_thread-gcc41-mt-1_42
endif

all: first-lib

first-lib: firstLib.cpp
        $(CXX) $(CXXFLAGS) -o $@ -I$(INCLUDEDIR) -L$(LIBDIR) $? $(LIBS) -lvixDiskLib

clean:
        $(RM) -f first-lib
  • make

で特にエラーにならなければ OK です
CentOS7 であれば特に必要なライブラリを別途インストール必要もなくコンパイルできると思います

実行

  • ./first-lib

で OK です
以下のように表示されると思います

0
0
0
0
capacity          = 62914560 sectors
number of links   = 1
adapter type      = LsiLogic SCSI
BIOS geometry     = 0/0/0
physical geometry = 3916/255/63
Transport modes supported by vixDiskLib: file:nbdssl:nbd

0 の部分は各 API が返却する VixError 変数の値を表示しています
0 が正常終了なのでここが 0 以外であれば何かしら間違っているので修正する必要があります

自分の場合一番ハマったのは VixDiskLib_ConnectEx でした
パラメータの指定に vmxSpec が必須なのがどこにも記載がなくTry&Error を繰り返して判明しました
また初めは vCenter ではなく ESXi にアクセスしようとしていたのですが、それだとうまく行きませんでした
ドキュメントには ESXi でもいけるとあるのですがどうやってもできなかったので諦めて vCenter にアクセスするようにしました

最後に

VDDK API を使って vmdk にアクセスするサンプルコードを作ってみました
もしかしたら探せば同じようなコードが出てくるかもしれませんが自分の中では、ここで紹介している記事しかないかなと思います (少なくとも日本語では)
ググって調べるといろいろ分かるのですがこの VDDK API はベンダー製品や OSS 製品でも使われているようです
それらで使われている方法を参考にするのも良いかもしれません

ただ全体として VDDK API の情報はかなり少ないと思います
自分からも少しでも情報発信できればと思います

0 件のコメント:

コメントを投稿