連載
» 2010年11月04日 00時00分 UPDATE

Inside Linux KVM(3):libvirt探訪(基礎編) (2/2)

[佐藤暁,レッドハット株式会社]
前のページへ 1|2       

VMの管理操作

 まず、VMに対する管理操作コマンドの一部を紹介します。

コマンド 管理操作
define VM のハードウェア仕様などを定義するXMLファイルからインスタンスを定義し、登録。この後、VMのXML定義ファイルが所定の場所(例:qemu/kvmの場合標準では/etc/libvirt/qemu/.xml)にインストールされる。
undefine VMの登録を外す、つまり削除する。そのVMのXML定義ファイルは削除される。
start VMを起動
destroy VMを強制停止(通常はこちらではなくVM内のOSを操作して正常停止させる)
dumpxml VMのXML定義を出力
edit VMのXML定義をエディタで編集
表5 VMに対する管理操作コマンド
$ sudo virsh start rhel-5-cluster-1
Domain rhel-5-cluster-1 started
$ sudo virsh dumpxml rhel-5-cluster-1 | head
<domain type='kvm' id='14'>
  <name>rhel-5-cluster-1</name>
  <uuid>7a85c498-9ae7-990e-0b57-93260a9637f7</uuid>
  <memory>262144</memory>
  <currentMemory>262144</currentMemory>
  <vcpu>1</vcpu>
  <os>
    <type arch='i686' machine='pc'>hvm</type>
    <boot dev='hd'/>
  </os>
(中略)
$ sudo virsh destroy rhel-5-cluster-1
Domain rhel-5-cluster-1 destroyed
$
VM管理操作の実行例

仮想ネットワークの管理操作

 次に、virshによるVMのためのリソースの管理操作の例として、仮想ネットワークについて一部のコマンドを紹介します。

コマンド 仮想ネットワーク管理操作
net-define <NETWORK_XML_FILE> 仮想ネットワークのXML定義ファイルからインスタンスを定義し登録。仮想ネットワークのXML定義ファイルは所定の場所(例:qemu/kvmの場合標準では/etc/libvirt/qemu/networks/.xml)にインストールされる。
net-undefine<NETWORK_NAME> 仮想ネットワークの登録を外す、つまり削除する。XML定義ファイルは削除される。
net-start<NETWORK_NAME> 仮想ネットワークを起動。ネットワークの開始とともに関連するサービス(dnsmasqなど)も開始/起動
net-destroy<NETWORK_NAME> 仮想ネットワークを強制停止
net-dumpxml<NETWORK_NAME> 仮想ネットワークのXML定義を出力
net-edit<NETWORK_NAME> net-edit <NETWORK_NAME>
表6 仮想ネットワーク操作のためのコマンド
$ sudo virsh net-list --all
Name                 State      Autostart
-----------------------------------------
net-1                active     yes
net-2                active     yes
net-3                active     yes
default              inactive   no
$ sudo virsh net-start default
Network default started
$ sudo virsh net-list
Name                 State      Autostart
-----------------------------------------
default              active     no
net-1                active     yes
net-2                active     yes
net-3                active     yes
$ sudo virsh net-destroy default
Network default destroyed
$ sudo virsh net-list
Name                 State      Autostart
-----------------------------------------
net-1                active     yes
net-2                active     yes
net-3                active     yes
$
仮想ネットワーク操作の実行例

 いかがでしょうか? VMの管理操作と仮想ネットワークの管理操作が非常に似通っていることがご理解いただけるかと思います。

libvirt APIを使ってみよう

 libvirt APIはCのライブラリとして提供されていますが、APIを試すだけの目的でCでコードを書くのは、少し気が重い作業作業かもしれません。そこでC APIの代わりに、標準でlibvirtソースツリーにも含まれるPythonバインディングを使ってみます(注8)。

 C APIと Python APIでは、言語の違いのため、多少APIの扱い方が違う部分もありますが、大筋では似ています。PythonでAPIを使う場合でも、CのAPIの利用例を見ると非常に参考になります。

 またVMの管理用のGUIツールであるvirt-managerや、VMへのOSのインストールを行うツールvirt-installは、いずれもlibvirt APIのPythonバインディングを使っていますので、これらのソースコードも参考になるでしょう。さらに、最近ではApplication Development Guideの内容も充実してきており、非常に参考になります。

 ここではvirshのソースコードを参照しながら、pythonでlibvirt APIを利用するコードを書いてみましょう。

注8:libvirt APIのバインディングはほかに、Perl、Java、Ruby、OCaml向けのものなどが利用できます。

libvirt API利用のための基礎知識

 APIの利用の手順はおおよそ次のとおりとなります。

  1. virConnectOpen* (C) / libvirt.open* (Python)に接続先を示すURI文字列を渡してVMMへ接続
  2. 接続を維持しつつAPIを呼び出し
  3. 接続クローズ

 接続先を表すURIは“xen:///”や“qemu:///system”というような表現となり、先頭部分の“xen”や“qemu”といった文字列からどのVMMにアクセスするかが選択され、VMMバックエンドが切り替えられます。

VMのステータス情報を取得

 簡単なものとしてまず“virsh domstate ”を実装してみましょう。“domstate”コマンドに該当するのは、virshのソースコード(tools/virsh.c)の以下の部分です。

/*
* "domstate" command
*/
static const vshCmdInfo info_domstate[] = {
    {"help", N_("domain state")},
    {"desc", N_("Returns state about a domain.")},
    {NULL, NULL}
};
static const vshCmdOptDef opts_domstate[] = {
    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
    {NULL, 0, 0, NULL}
};
static int
cmdDomstate(vshControl *ctl, const vshCmd *cmd)
{
    virDomainInfo info;
    virDomainPtr dom;
    int ret = TRUE;
    if (!vshConnectionUsability(ctl, ctl->conn))
        return FALSE;
    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return FALSE;
    if (virDomainGetInfo(dom, &info) == 0)
        vshPrint(ctl, "%s\n",
                _(vshDomainStateToString(info.state)));
    else
        ret = FALSE;
    virDomainFree(dom);
    return ret;
}

 要約すると、次のような処理を行っています。

  1. virConnectOpenAuth(libvirt API)でVMMに接続
  2. virDomainGetInfo(libvirt API)でVM(Domain)の情報を取得
  3. VM情報からステータスを取り出し、文字列表現に変えて表示

 これをPythonで同様に書いてみると、例えば次のように書けます(注9)。

#! /usr/bin/python
import libvirt
import sys
def domainStateToString(state):
  """@see http://libvirt.org/html/libvirt-libvirt.html#virDomainState
  """
  sts = ('no sate', 'running', 'blocked', 'paused', 'shutting down', 'shut off', 'crushed')
  return sts[state]
if len(sys.argv) < 2:
  print >> sys.stderr, "Usage: %s VM_NAME" % sys.argv[0]
  sys.exit(1)
vm_name = sys.argv[1]
conn = libvirt.openReadOnly(None) # Choose it instead of libvirt.openAuth.
if conn is None:
  print >> sys.stderr, "Could not connect to VMM"
  sys.exit(1)
try:
  vm = conn.lookupByName(vm_name)
  (st,_maxmem,_mem,_nrcpus,_cputime) = vm.info()
  print "%s: %s" % (vm_name, domainStateToString(st))
except:
  print >> sys.stderr, "Could not get the info of vm %s" % (vm_name,)
$ sudo python domstate.py rhel-5-4-guest-1
[sudo] password for kvmuser:
rhel-5-4-guest-1: running
$
domstateコマンドの実行例

起動中のVM一覧を表示

 次に“virsh list”に相当するPythonコードを書いてみましょう。“list”コマンドに該当するのはvirshのソースコード(tools/virsh.c)のcmdList関数です。こちらを参考に、Pythonでまねをして書いてみると、例えば次のように書けます。

#! /usr/bin/python
import libvirt
import sys
def domainStateToString(state):
  """@see http://libvirt.org/html/libvirt-libvirt.html#virDomainState
  """
  sts = ('no sate', 'running', 'blocked', 'paused', 'shutting down', 'shut off', 'crushed')
  return sts[state]
if len(sys.argv) < 2:
  uri = 'qemu:///system' # default: KVM/qemu
else:
  uri = sys.argv[1]
conn = libvirt.open(uri)
if conn is None:
  print >> sys.stderr, "Could not connect to VMM: %s" % uri
  sys.exit(1)
try:
  vms = [(i, conn.lookupByID(i)) for i in conn.listDomainsID()]
  res = [(i, vm.name(), domainStateToString(vm.info()[0])) for (i,vm) in vms]
  print "%3s %-20s %s" % ('Id', 'Name', 'State')
  print "----------------------------------"
  for r in res:
    print "%3s %-20s %s" % r
except:
  print >> sys.stderr, "Could not get the list" 
注9:ただしここでは、libvirt.openAuthの代わりに認証プロセスの実装が必要ないlibvirt.openReadOnlyで代用しています(root権限で実行する必要があります)。

libvirt API以外の方法でアクセスする

 お好みのプログラミング言語のlibvirt APIのバインディング実装がない場合、バインディングを実装する以外にも、制限はありますがいくつか方法が考えられます。

  • 希望のプログラミング言語内からvirshを呼び出してその出力結果を解析し、利用
  • libvirt-CIM(CIM プロバイダ)またはlibvirt-qpid(QMFインターフェイス)経由で利用

 前者は機能の制限はありますが、ほとんどのプログラミング言語で比較的容易に実現可能でしょう。例として、筆者が最近試しはじめているHaskellによる実装(注10)をサンプルとして挙げておきます。

 後者は、libvirt APIをそれぞれCIM(注11)とQMF(注12)の枠組みの中で扱えるようにするインターフェイスを利用する方法です。利用にはそれぞれ対応するパッケージ(libvirt-cim、libvirt-qpid)の追加インストールと相応のセットアップ作業が必要になります。これらについては筆者には十分な知識がありませんので、以下、参考程度に各種URLを挙げるにとどめます。

 libvirt-CIMについてはおそらく次などが参考になるでしょう。

関連リンク
▼Managing KVM with CIM(Kaitlin Rupert, Linux Plumbers Conference 2009 スライド資料)
http://linuxplumbersconf.org/2009/slides/Kaitlin-Rupert-Plumbers_2009_Managing_KVM_with_CIM.pdf
▼libvirt-cim setup instructions
http://wiki.libvirt.org/page/Libvirt-cim_setup

 libvirt-qpidについては文書はほとんど見当たりませんが、qpidのsubversionリポジトリにqpid のRubyバインディングによるサンプル実装があるようです。

関連リンク
▼libvirt-qpid(QMF)のRubyによるサンプルコード
https://svn.apache.org/repos/asf/qpid/trunk/qpid/ruby/examples/qmf-libvirt.rb

注10:筆者はHaskell修行中で慣れていないため非常に拙い実装ですが、雰囲気は感じとっていただけるかと思います。
注11:http://www.dmtf.org/standards/cim/
注12:https://cwiki.apache.org/qpid/qpid-management-framework.html


 以上、libvirtの概要とvirshを通したVMの管理方法、libvirt APIの利用方法について解説しました。次回は、libvirt開発最前線の状況をお伝えします。

筆者紹介

r5portrait_satoh.jpg

佐藤 暁

レッドハット株式会社RHELコンサルタント。Linuxカーネルから Python/JavaによるWebアプリケーションまで、ソースコードを探りつつ、システム管理や標準化など コンサルテーション業務をこなす日々。


前のページへ 1|2       

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。