読者です 読者をやめる 読者になる 読者になる

うまいぼうぶろぐ

linuxとhttpdとperlのメモ

perl Sys::Virt でlibvirt APIを叩いてKVM 仮想マシンを操作する

Sys::Virt - libvirtperl バインディングvirt-manager で出来るようなストレージの設定や仮想マシンの起動、停止、削除、設定変更などが可能。(自分で確認したのは仮想マシンを操作するSys::Virt::Domain のみ)

久しぶりに触ろうとしたら忘れすぎて悲惨だったのでおさらいしておく。

install

OSのlibvirt に依存しているので、cpanm Sys::Virt などとして最新版を入れようとしても失敗するのでOSパッケージのものを使う。(もしくはlibvirtをsourceから取って最新のものをinstallしてからcpanm Sys::Virt するか)

RHEL/CentOS/SL
# yum install libvirt
# yum install perl-Sys-Virt


debian/ubuntu
# apt-get install libvirt-bin libvirt0
# apt-get install libsys-virt-perl

使い方

  • perldoc Sys::Virt
  • perldoc Sys::Virt::Domain
  • その他のperldoc Sys::Virt::*
接続

remote hostにログインする時はsshを使って qemu+ssh://hostname/system などで接続する。認証情報をSys::Virtに渡すことも出来るけど、sshの場合は公開鍵を作って ~/.ssh/config に設定しておいたほうが色々と楽になる。Sys::Virt->new で接続に失敗すると例外で落ちるのでeval しておくなど。

my $user = "user";
my $host = "kvm.example.com";
my $uri = "qemu+ssh://$user\@$host/system";
my $vmm;
eval {
  #$vmm = Sys::Virt->new(uri => $uri, readonly => 1);
  $vmm = Sys::Virt->new(uri => $uri);
};
if ($@) {
  die "$@";
}
情報取得

$vmm->list_domains, $vmm->list_defined_domains などで仮想マシンのオブジェクト(Sys::Virt::Domain)の配列を取得する。list_domainsは稼働中な仮想マシン、list_defined_domainsは停止中の仮想マシンのSys::Virt::Domain オブジェクトを返す。

my @doms = $vmm->list_domains()
  Return a list of all domains currently known to the VMM. The elements in the
  returned list are instances of the Sys::Virt::Domain class.

my @doms = $vmm->list_defined_domains()
  Return a list of all domains defined, but not currently running, on the VMM. The
  elements in the returned list are instances of the Sys::Virt::Domain class.

仮想マシンの名前,uuid, cpu/memory/state を取得。この辺は/etc/libvirt/qemu/仮想マシン.xml の情報と同じ。$dom->get_info はハッシュリファレンスで返ってくるので手抜きしてdumpしてる例。

use Data::Dump qw(dump);
for my $dom ($vmm->list_domains, $vmm->list_defined_domains) {
  ## see perldoc Sys::Virt::Domain
  print "name: ", $dom->get_name, "\n";
  print "uuid: ", $dom->get_uuid_string(), "\n";
  ## $dom->get_info returns a hash reference
  dump $dom->get_info;
  print "\n";
}


この辺までを実行するとこうなる。
# foo 起動中、bar 停止中、baz 一時停止中(suspend) の仮想マシン

$ perl sysvirt.pl
name: foo
uuid: f33fa104-dbc3-5328-49c2-474bf3733664a
{
	cpuTime   => "66750000000",
	maxMem    => 2097152,
	memory    => 2097152,
	nrVirtCpu => 2,
	state     => 1,
}

name: bar
uuid: 19b95335-806f-53f1-0149-fae39fbd9872
{
	cpuTime   => 0,
	maxMem    => 2097152,
	memory    => 2097152,
	nrVirtCpu => 2,
	state     => 5,
}	
	
name: baz
uuid: 19b95335-806f-53f1-0149-f2ae39fbd981
{
	cpuTime   => "81660000000",
	maxMem    => 1048576,
	memory    => 1048576,
	nrVirtCpu => 1,
	state     => 3,
}

stateはperldoc Sys::Virt::Domain 参照。

my $info = $dom->get_info()
(snip)
  state
             The execution state of the machine, which will be one of the constants
             &Sys::Virt::Domain::STATE_*.

とあるように判別するときは直接数字を指定するではなくて、この関数を実行して値とってくる。関数を叩くと並んでいる順に0~6までの数値が返ってくる。

DOMAIN STATE
     The domain state constants are useful in interpreting the "state" key in the hash
     returned by the "get_info" method.

     Sys::Virt::Domain::STATE_NOSTATE
         The domain is active, but is not running / blocked (eg idle)

     Sys::Virt::Domain::STATE_RUNNING
         The domain is active and running

     Sys::Virt::Domain::STATE_BLOCKED
         The domain is active, but execution is blocked

     Sys::Virt::Domain::STATE_PAUSED
         The domain is active, but execution has been paused

     Sys::Virt::Domain::STATE_SHUTDOWN
         The domain is active, but in the shutdown phase

     Sys::Virt::Domain::STATE_SHUTOFF
         The domain is inactive, and shut down.

     Sys::Virt::Domain::STATE_CRASHED
         The domain is inactive, and crashed.

停止/起動
  • $dom->create();
  • $dom->shutdown();
  • $dom->destroy();
  • $dom->suspend();
  • $dom->resume();

あたり。shutdownは電源ボタンを押すのと同じなので、仮想マシン側でapicdを動かしておかないと意味がない。 destroyは強制停止。


ex: 停止中の(正常に停止状態にある)仮想マシンを起動する

for my $dom ($vmm->list_domains, $vmm->list_defined_domains) {
  if ($dom->get_info->{state} == &Sys::Virt::Domain::STATE_SHUTOFF) {
    $dom->create();
    print $dom->get_name, " created\n";
  }
}
code

また忘れたら嫌だからgist に置いておいた。