Rubyでコマンドラインから与えられたオプションで仮想マシンを管理するでござる。

Ruby逆引きレシピAdvent Calendarの5日目ということで、実に1年以上ぶりにBlog書きますよ。
このレシピ本には結構お世話になっていて、今でも結構見てます。
勿論実際コード書くときはドキュメントやgoogle様を併用するわけですが、この本をパラパラめくってると、色々インスピレーションが湧いていいですね。

で、お題ですが今回はインフラエンジニアらしく、KVMを管理するlibvirtAPIRubyから叩けるコマンドラインスクリプトを作りたいと思います。
ターゲットページは #058 『コマンドラインから与えられたオプションを解析したい』です。


今回の環境はこんな感じ

OS: Redhat Enterprise Linux 6.0 2.6.32-71.el6.x86_64
ruby: 1.8.7 (2010-06-23 patchlevel 299) [x86_64-linux]
ruby-libvirt: 0.2.0-1.el6.x86_64

ruby-libvirtについては、libvirt.org/rubyから git clone た後ビルドして各自こさえてくださいね。


あ、余談ですがRHELじゃなくてFedora14だと既にリポジトリにありますので

yum install ruby-libvirt.x86_64

Fedoraな方はコレでもオッケーです。


ところでlibvirtといえば、pythonなわけで、コマンドラインから管理するなら virsh という超絶便利なshellすらあるのになんでわざわざrubyで超機能限定版を再実装するのかというと、それは深い意味があるようでないようで、実はコマンドラインから扱いたいんじゃなくてRailsのcontroller的な所に処理の部分だけ持ってって、 /vm_name/power_on みたいなURIに引数付けて Ajax で post 飛ばすと仮想マシンがガーっと立ち上がったり新規に作成できたり電源落とせたりとか、まぁ要は某石狩データセンターなところのVPSの管理画面みたいなのが作れます、というか既に作ったんだけど、それネタにしたら全然レシピ本と関係ないし、やべぇ俺プログラマーじゃねーし、とか思ったから簡単そうなので行こうぜ、という事でコレを選んでみたわけだが、アレこれ意外とスゲー使えるじゃん的な。


さて、前置きが揃ったところで早速レシピを参考にちょちょっと書いてみました。
なんかエラー処理が甘い感じだし、ミョーに無駄が多い気もしますが、まぁいいでしょう。
こう言ったちょっとしたものを15分もかければ作れてしまうのがRubyのいい所ですね。


vm_power.rb

#!/usr/bin/ruby
require 'libvirt'
require 'optparse'

OPTIONS = {
}

ARGV.options do |opts|
  opts.on("-r", "--remote <HOST NAME>", "libvirtd host, ex: root@localhost.localdomain") {|host|
    OPTIONS[:host] = host
  }

  opts.on("--on", "--on <VM NAME>", "VM Power ON") {|p_on|
    OPTIONS[:p_on] = p_on
  }

  opts.on("--off", "--off <VM NAME>", "VM Shutdown") {|p_off|
    OPTIONS[:p_off] = p_off
  }
  opts.parse!
end


if OPTIONS[:host] then
  conn = Libvirt::open("qemu+tcp://#{OPTIONS[:host]}/system")

  if OPTIONS[:p_on] then
    begin
      vm = conn.lookup_domain_by_name(OPTIONS[:p_on])
      vm.create
    rescue => ex
      puts "Error #{ex.message}"
    else
      puts  "Power ON #{OPTIONS[:p_on]}"
    ensure
      unless conn.nil?
        conn.close
      end
    end
  elsif OPTIONS[:p_off] then
    begin
      vm = conn.lookup_domain_by_name(OPTIONS[:p_off])
      vm.shutdown
    rescue => ex
      puts "Error: #{ex.message}"
    else
      puts "Power OFF: #{OPTIONS[:p_off]}"
    ensure
      unless conn.nil?
        conn.close
      end
    end

  else
    puts "Help: vm_power.rb -h"
  end
end


使い方はこんな感じですね。

# ./vm_power.rb -h
Usage: vm_power [options]
    -r, --remote          libvirtd host, ex: root@localhost.localdomain
        --on                VM Power ON
        --off               VM Shutdown

# ./vm_power.rb -r root@hoge.localdomain --on vm1
Power ON vm1

# ./vm_power.rb -r root@hoge.localdomain --off vm1
Power OFF: vm1

基本的な考え方は、 OptionParser#on でオプションを登録して、それに対応する動きを書く感じになるんですね。
で、最後に OptionParser#parse! メソッドでそのオプションに該当する動作を実行するみたいです。
ぶっちゃけそこでは、ほとんど何もしてないんですが。


というか最後の怒涛のif文はどう見ても綺麗じゃないですね、本当にありがとうございました。

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

Ruby 逆引きレシピ すぐに美味しいサンプル&テクニック 232 (PROGRAMMER’S RECIPE)

はい、という訳で積ん読してる方は引張り出してみるなり、まだの人は書店やamazonにお急ぎいただければと思います。

追記 Wed Dec 15 18:54:02 JST 2010

どうやら12日にruby-libvirt 0.3.0がReleaseされていたようですね。
ちなみにこの記事は 0.2.0前提で書きましたが、0.3.0でも動作することを確認しました。
あと、gitからcloneしなくとも、rubygems.orgに登録されていたので、そちらを利用しても良いですね。

gem install ruby-libvirt

です。