serverspec に before/after が欲しいなーと思っていたところ、cucumberのstepsでserverspecをつかうを拝見しまして。
cucumber ならシリアルに実行するので前後の処理を書けるのでこれでいいやと。step から ansible 呼べばインストールも終わるし一石二鳥。ということで試しに MixIn してみました。なお、ansible を呼ぶ方法はこちらを参考にさせて頂いてます。 6月15日追記 強引な方法ですが ssh を使えるように変更しました。ローカルで実行する場合 set_serverspec_target() は不要です。詳細は末尾にて。
require 'test/unit/assertions'
require 'serverspec'
require 'net/ssh'
World(Test::Unit::Assertions)
World(Serverspec::Helper::Type)
include SpecInfra::Helper::Ssh
include SpecInfra::Helper::Debian
# serverspec-init の spec_helper.rb を改変
def set_serverspec_target(host)
c = SpecInfra.configuration
if ENV['ASK_SUDO_PASSWORD']
require 'highline/import'
c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
else
c.sudo_password = ENV['SUDO_PASSWORD']
end
if c.host != host
c.ssh.close if c.ssh
c.host = host
options = Net::SSH::Config.for(c.host)
user = options[:user] || Etc.getlogin
c.ssh = Net::SSH.start(host, user, options)
end
end
フィーチャをさくっと書いてしまいます。
フィーチャ: httpd をインストールしてチェック
背景:
前提 対象のサーバは "myhost" である
シナリオ: インストールしてチェック
もし "httpd" をインストールする
ならば "httpd" がインストールされていること
いくらなんでももうちょっとマシなテストを書けないものか。。。
と、とにかくステップはこんなかんじで。
前提(/^対象のサーバは "(.*?)" である$/) do |arg1|
@server = arg1
server_spec_target(@server)
end
もし(/^"(.*?)" をインストールする$/) do |arg1|
output = `ansible all -i #{@server}, -m yum -a 'name=httpd state=present'`
assert $?.success?
end
ならば(/^"(.*?)" がインストールされていること$/) do |arg1|
package(arg1).should be_installed
end
2014/6/15追記
ssh が動かなくてすごい苦労しました(3時間ぐらい ServerSpec, SpecInfra, RSpec を読み込んで)。理由を調べたところ SpecInfra が RSpec.configuration.add_setting :ssh してますが、この設定を cucumber からコールした場合に読めないためのようです。結果として RSpec.configuration.ssh が nil になってしまってます。SpecInfra は missing_method を使って RSpec.configuration からデータを取り出しているので、もう諦めて SpecInfra.configuration にぶち込んでしまったわけです。
なんにせよ動いたので、次はマルチホストに挑戦する予定です。describe の呼び方も宿題。