serverspecをグループ分けして実行する方法

serverspecは、デフォルトの設定だとhost毎にspecファイルを書かなければいけません。

spec
├── spec_helper.rb
└── example.com
    └── httpd_spec.rb

そのため、同じミドルウェアがインストールされている場合、同じソースを書かなければいけないのが少し面倒くさいです。

spec
├── spec_helper.rb
├── example.com
│   └── httpd_spec.rb // 同じspecファイル
└── example2.com
    └── httpd_spec.rb // 同じspecファイル

これを解決する方法が公式に書いてありました。

http://serverspec.org/advanced_tips.html

グループ分けしてspecファイルを管理する

app、base、dbなど役割に応じてディレクトリを作成して、specファイルを分けます。

spec
├── app
│   └── ruby_spec.rb
├── base
│   └── users_and_groups_spec.rb
├── db
│   └── mysql_spec.rb
├── proxy
│   └── nginx_spec.rb
└── spec_helper.rb

Rakefileを修正

Rakefileに、host毎のテストケースを先ほどのディレクトリ単位で指定します。(複数組み合わせることも可能)

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

##### いじるのは、ここから #####
hosts = [
  {
    :name  => 'proxy001.example.jp',
    :roles => %w( base proxy ),
  },
  {
    :name  => 'proxy002.example.jp',
    :roles => %w( base proxy ),
  },
  {
    :name  => 'app001.example.jp',
    :roles => %w( base app ),
  },
  {
    :name  => 'app002.example.jp',
    :roles => %w( base app ),
  },
  {
    :name  => 'db001.example.jp',
    :roles => %w( base db ),
  },
  {
    :name  => 'db002.example.jp',
    :roles => %w( base db ),
  },
]
##### ここまで #####

hosts = hosts.map do |host|
  {
    :name       => host[:name],
    :short_name => host[:name].split('.')[0],
    :roles      => host[:roles],
  }
end

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

class ServerspecTask < RSpec::Core::RakeTask

  attr_accessor :target

  def spec_command
    cmd = super
    "env TARGET_HOST=#{target} #{cmd}"
  end

end

namespace :serverspec do
  task :all => hosts.map {|h| 'serverspec:' + h[:short_name] }
  hosts.each do |host|
    desc "Run serverspec to #{host[:name]}"
    ServerspecTask.new(host[:short_name].to_sym) do |t|
      t.target = host[:name]
      t.pattern = 'spec/{' + host[:roles].join(',') + '}/*_spec.rb'
    end
  end
end

spec_helper.rbを修正

spec_helper.rbを下記の内容に書き換えます。

require 'serverspec'
require 'net/ssh'

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

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

実行してみる

全部のホストを実行
$ bundle exec rake serverspec:all 
ホストを指定して実行

Rakeファイルに記入したhost名の最初の「.(ドット)」までがprefixとなります。

$ bundle exec rake serverspec:proxy001
$ bundle exec rake serverspec:app001

Rakefileに直接書くのが嫌な人は

YAMLにhostを書いて、管理したりする方法もあるそうです。