Posted on Apr 30
Serverspec について改めて調査していたら Specinfra という Serverspec のバックエンドで実行しているコマンド群を抜き出した(という認識)ツールを知った。
かなり今更感が否めないが…こちらの資料を拝見して…
OS / ディストリビュージョン毎のコマンドの差異これらを吸収してくれるフレームワーク
という一文(スライドでは二枚分)に「おおっ」と思ったのでとりあえず手を動かすことにした。
作者の @gosukenator さんのこちらの記事によると Serverspec や configspec を作る際に共通する以下の処理を別の gem にしたのが Specinfra のようだ。
exec リモートホストの場合は SSH 等の実行形式を抽象化した backend と呼ばれているレイヤーOS ごとに OS に適したコマンドを返す commands と呼ばれているレイヤーproperties や configuration というヘルパーメソッド3 つ目のヘルパーメソッドについては実行環境に応じた必要な設定を行ってくれる(足りないものがあればエラーとなって注意してくれる)メソッドという認識。(例えば include SpecInfra::Helper::Lxc とすれば lxc の gem の有無をチェックしてくれたりと…もちろん、それだけでは無いと思うが)
こちらに倣って試してみたいと思う。
インストールした環境は MacOS X 10.9 Marvericks に今更の Boxen 経由(!)でインストール。
ruby::gem { "specinfra for 2.0.0-p247":
gem => 'specinfra',
ruby => '2.0.0-p247'
}
上記のように specinfra をインストールするマニフェストを書く。gem install specinfra でもぜんぜんオッケー。
インストールが終わったら早速 pry を起動して Specinfra を利用してみる。
チュートリアルはありませんが、serverspecのソースといつものspec_helper.rbを見れば大体つかめます。
@sawanoboly さんが上記のように書かれているので、手元の serverspec で生成した spec_helper.rb を見てみると SpecInfra の文字が見える。これが Serverspec がバックエンドで Specinfra が動いている証。
require 'serverspec'
include SpecInfra::Helper::Exec
include SpecInfra::Helper::DetectOS
require 'serverspec' とあるが serverspec.rb 内部で requier 'specinfra' とされているのも serverspec のソースから読み取れた。ということで、pry を起動して以下を実行して Specinfra を利用する準備を行う。

準備も整ったところで backend のメソッド達を呼び出してみる。
backend.methods
以下のようにズラズラーと backend で利用出来るメソッド達が表示される。

おお。
では、メソッドの中から run_command なんか試してみたりする。
backend.run_command('pwd')
以下のように pwd コマンドの実行結果を含んだ結果が出力された。

ついでに、先ほどの backend.methods から commands というメソッドを利用して、さらに…
backend.commands.check_running('httpd')
としてみると…以下のように backend.check_running('httpd') を実行する際に裏で実行される OS のコマンドが表示された。

ああ、これが各 OS のコマンドを抽象化しているということなのかな。
横領ではなくて応用。まだまだちゃんと Specinfra の事は知らないけど pry から触っていて色々とやりたくなってきたので簡単に試してみた。
適当に構築した Docker コンテナホストに対して Serverspec 的なことを実行してみる。
以下のスクリプトは見ての通り、
httpdsshdntpdそれぞれのプロセスが起動しているかをチェックするもの。
#!/usr/bin/env ruby
require 'specinfra'
require 'net/ssh'
include SpecInfra::Helper::Ssh
include SpecInfra::Helper::DetectOS
SpecInfra.configuration.ssh = Net::SSH.start('localhost', 'sshuser', {:port => '49156', :password => 'sshuser'})
PROCESSES=['httpd','sshd','ntpd']
PROCESSES.each do |process|
c = backend.check_running("#{process}")
if "#{c}" == "true"
puts "#{process} is running"
else
puts "#{process} is not running"
end
end
実行結果は下記の通り。

おお、やっていることはまさに Serverspec そのもの!Serverspec も裏側ではこのようなことが行われている…という認識を持てた。
Specinfra は Backend として以下のような環境が利用出来る。(他にもある)
sshlxcdockershellscriptということで…試してみた。尚、Backend として docker を利用する場合には docker-api の gem が必要になるのでインストールする。
sudo gem install docker-api --no-ri --no-rdoc -V
インストールが終わったら、例のごとく pry ではじめてみる。
require 'specinfra'
require 'docker'
を実行すると…

ふむ。次にヘルパーメソッド(と呼ぶのかな?)を include する。
include SpecInfra::Helper::Docker
include SpecInfra::Helper::RedHat
を実行すると…

次に Docker API の URL を指定してからコンテナイメージを指定する。
Docker.url = 'http://127.0.0.1:4243'
SpecInfra.configuration.docker_image = 'centos'

この状態から backend.methods を叩くと…

ほうほう。では run_command あたりを。
backend.run_command ('ls')
以下のように centos コンテナ内で ls を実行した結果が返ってきた。

おお、今度は install ('httpd') あたりを。
backend.install ('httpd')
以下のようにコンテナ内で Apache を yum install httpd でインストールした結果が返ってきた。

ファンタスティック!
上記のように Specinfra 内で抽象化されたコマンドで Docker コンテナ内に Apache をインストールすることが出来るのを確認した。
OS のコマンドの違いを抽象化するという考え方にとても共感出来るし、Specinfra はその方法論の一つを具現化したものだと思うSpecinfra を触ることで Serverspec が裏側でどんなことをやっているかが少し解ったRuby 力の低さから用語の使い方や認識に誤りがあると思われるが…も少し触ってみる2014 かっぱのほげふが