20
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

serverspec で複数ホストの指定を簡単にしてみた

Last updated at Posted at 2014-07-11

serverspec で複数ホストを指定する方法が、本家のサンプルにありますが、そのままコピペしてしまうと1つ1つホスト名を書くことになります。本家 → How to share serverspec tests among hosts

こちとら数百台テストしたいときもあるので、こんなことやってらません。ということで、pdsh ライクにレンジを指定して簡単にホストを指定できるようにして見ました。

まず、本家のサンプル通りに Rakefile と spec_helper.rb を書いておきます。

Rakefile と同じ所に、次のような pdhosts.rb を作成します。

pdhosts.rb
def gen_hosts(pattern)
   
  _range = pattern.scan(/\[.*\]/)

  # Return the pattern as is because no range specified
  return pattern if _range.size == 0

  # Multiple geometry of ranges is not supported
  if _range.size > 1
    raise "Invalid argument: #{pattern}"
  end

  range = _range.first.gsub(/\[|\]/,'')
  hosts = []

  # parse each range
  range.split(',').each do |range2| 
    first, second = range2.split('-')
    second = first if second.nil?
    for num in Range.new(first, second)
      hosts << pattern.gsub(/\[#{range}\]/, num)
    end
  end

  return hosts

end


def pdhosts(raw_hosts)

  # split to host patterns divided by ","
  patterns = raw_hosts.scan(/[^,]*\[[0-9,\-]*\][^,]*|[^,]*/).select{|s| s != ""}

  patterns.map{ |s| gen_hosts(s) }.flatten

end

pdhosts は、pdsh の -w オプションで指定するようにレンジを指定できます。ansible と違ってコロンではなく、以下のようにハイフンとカンマを使います。

  • proxy[001-008].example.jp
  • web[1,2,5-10].example.jp

これを文字列として pdhosts に渡せば全部展開してくれます。

例として、本家の Rakefile にあるホスト指定を書き換えてみました。ホスト指定以外の他の部分はそのまま使うことができますので、残しておく必要があります。

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

### ここから ###

require './pdhosts'

roles = [
  {
    :hosts => 'proxy[001,002].example.jp',
    :roles => %w( base proxy ),
  },
  {
    :hosts => 'app[001-010].example.jp',
    :roles => %w( base app ),
  }
  {
    :hosts  => 'db[001,002].example.jp',
    :roles => %w( base db ),
  }
]

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

### ここまで ###

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

task :default => :spec

flatten しまくってる自分が嫌になりますが。まずは動いてるからいいかなーと。

残念なことに net-ssh を使ってるのでシーケンシャルなんですね。net-ssh-multi を使うように改変したい。。。
訂正:コメントでご指摘いただきました。rake -j もしくは rake -m で同時に複数実行できるんですね。素晴らしい。(rake --help を読み直し中・・・)

20
21
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?