serverspecに手を出してみた

※2014/4/15 追記
ヒアドキュメントによる複数行比較(擬似diff)についてはtagomorisさんの下記がマージされれば使えるようになるはず。
https://github.com/serverspec/serverspec/pull/387


ホストを同じ構成で複数台、且つ構築時期が微妙に違うというものがあるのでそろそろ設定チェック方式を決めないとなあという事情があったのでずっと使おう使おう思ってた、serverspecを使うことにしました。
とりあえずテストを流す上での核となるRakefile/spec_helper.rbをメモ。
1回作るとありがたみをすごく感じます。mizzy さんの素晴らしいツールに感謝しきりです。
OS部分のテストも大体できたので、今後はOracleの設定部分を作っていく予定。
 

  • 参考

http://serverspec.org/
http://rubydoc.info/gems/rspec-core/RSpec/Core/RakeTask#fail_on_error-instance_method
 

  • 試したバージョン

CentOS release 6.5
ruby 1.9.3p545 (2014-02-24 revision 45159) [x86_64-linux] ※2系にあげないとな…
specinfra (0.8.0)
serverspec (0.15.5)
 

  • Rake構成

IPアドレスなどの可変部分を外出ししたかったので、http://serverspec.org/advanced_tips.html の「How to use host specific properties」を基本にしました。
 

  • properties.yml

仮テストなので適当です。

vora:
  :roles:
    - ntp
    - account
    - network
  :mngip: 192.168.xxx.xxx

 

サンプルほぼそのままですが「t.fail_on_error = false」入れて、rspec が failed になっても次のホストに進めるようにしています。

require 'rake'
require 'rspec/core/rake_task'
require 'yaml'

properties = YAML.load_file('properties.yml')

desc "Run serverspec to all hosts"
task :spec => 'serverspec:all'

namespace :serverspec do
  task :all => properties.keys.map {|key| 'serverspec:' + key.split('.')[0] }
  properties.keys.each do |key|
    desc "Run serverspec to #{key}"
    RSpec::Core::RakeTask.new(key.split('.')[0].to_sym) do |t|
      ENV['TARGET_HOST'] = key
      t.fail_on_error = false
      t.pattern = 'spec/{' + properties[key][:roles].join(',') + '}/*_spec.rb'
    end
  end
end

 

  • spec_helper.rb

これもサンプルほぼそのままですが、パスワード入力でのsshログインさせる方向のため、ASK_LOGIN_PASSWORD 周りを入れています。

require 'serverspec'
require 'pathname'
require 'net/ssh'
require 'highline/import'
require 'yaml'

include Serverspec::Helper::Ssh
include Serverspec::Helper::DetectOS
include Serverspec::Helper::Properties

properties = YAML.load_file('properties.yml')
if ENV['ASK_LOGIN_PASSWORD']
  inputpassword = ask("\nEnter login password: ") { |q| q.echo = false }
else
  inputpassword = ENV['LOGIN_PASSWORD']
end

RSpec.configure do |c|
  c.host  = ENV['TARGET_HOST']
  set_property properties[c.host]
  options = Net::SSH::Config.for(c.host)
  options[:password] = inputpassword
  user    = options[:user] || Etc.getlogin
  c.ssh   = Net::SSH.start(c.host, user, options)
  c.os    = backend.check_os
end

 

  • はじめてやる上でハマったことやその他やったことのまとめ

・ファイルの内容を全比較する場合、match_~checksumがベースと思われるがレポートにファイル内容を出すにはファイルの内容をdiffするような形にしたい。its(:content)にガツっと書くのがいいのかな?
・複数テストを用意したときに failed になった場合でも先に進めるようにするにはどーすれば?
 →RSpecの「fail_on_error = false」で対応。たどり着くまでずいぶん時間がかかったorz
・Service resource typeで意図的に無効にしたサービスをテストするためにbe_disabledが欲しいと思った
 →it { should_not be_enabled } でできる。
  が、OSによってはbe_enabledの実装次第で不適切になる可能性はあるので、その時は be_disabled を実装したほうがよいかもしれない。redhat/solarisは実装もすぐできた。
・Rake/RSpec周りがはじめてだったので色々調べながらで手間取った。けど、少しだけRake/RSpecの理解も進んで良かった。…けどまだまだ知らないことばかり。1回Railsアプリ作るしかないか?