31
31

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で完結するテスト駆動インフラ構築 (Test-Driven-Infrastructure with serverspec)

Last updated at Posted at 2013-10-11

この記事は最終更新から1年以上経過しています。 気をつけてね。

サーバの構築状況を、手動確認の段取りでチェックするserverspec、使いやすくて評判ですね。

注: このエントリはほぼネタなのであまり参考にしてはいけません。

さて、テスト駆動開発という手法は皆さん既にご存知でしょう。今日は折角テストツールがあるのですからサーバ構築をテスト駆動でやってみましょう。

まずFailするSpecサンプル

こちらはパッケージnginxがインストールされているかテストするserverspecのサンプルです。

nginx_spec.rb
require 'spec_helper'

describe package('nginx') do
  it { should be_installed }
end

Failすることを確認

Failからはじまるテスト駆動、serverspecはテストに使ったコマンドも表示してくれます。

run_rspec_fails
Failures:

  1) Package "nginx" 
     Failure/Error: it { should be_installed }
       dpkg -s nginx && ! dpkg -s nginx | grep -E '^Status: .+ not-installed$'
       Package `nginx' is not installed and no info is available.
Use dpkg --info (= dpkg-deb --info) to examine archive files,
and dpkg --contents (= dpkg-deb --contents) to list their contents.
       expected Package "nginx" to be installed
     # ./spec/xxx.xxx.xxx.xxx/nginx_spec.rb:4:in `block (2 levels) in <top (required)>'

Finished in 1.01 seconds
1 examples, 1 failures

目出度くFailしました、ではこれを満たすようにサーバ構築のコードを書きましょう!

Rescueせよ

(重ねて言いますがあまり真面目に受け取らないでください。)

構築には何を使いましょう、chef?puppet? いえ今日は趣向をこらして、Failを検知できるRspec(serverspec)自身に直させましょう。

ということでnginx_spec.rbをこの様に変更です。

nginx_converge_spec.rb
require 'spec_helper'

describe package('nginx') do
  it {
    begin
      should be_installed
    rescue => e
      puts e.message
      puts "======= Installing Nginx..."
      cmd = Serverspec::Type::Command.new('apt-get update && apt-get install -y nginx')
      expect(cmd.return_exit_status?(0)).to be_true
    end
  }
end

nginxのshould be_installedが例外を吐いたらrescueしてサーバ状態のつじつまを合わせにいきます。
コマンド実行にもserverspecのマッチャを使うことで、楽にエラーチェックができますね!

serverspecで完結、テスト駆動

では初めにFailしたのと同じ状態のサーバにserverspecを実行してみます。

run_rspec_converge
$ rspec -fd

Package "nginx"
expected Package "nginx" to be installed
======= Installing Nginx...
  should be true

Finished in 13.42 seconds
1 example, 0 failures

expected Package "nginx" to be installed と、rescue側に入ってつじつま合わせが走りました。
すんだらもう一度serverspecを実行してみます。

run_rspec_up_to_date
$ rspec -fd

Package "nginx"
  should be installed

Finished in 1.03 seconds
1 example, 0 failures

should be installed #=> true、できました。まさに冪等な収束。

終わりに

テスト駆動はソフト開発でもしばしば難題と言われますが、インフラはこのくらい緩めな手法でもアリかな。


追記

chef-soloを導入してcommunity cookbookから rabbitmq のインストール状態を確認し、入ってなければ勝手にインストールするserverspecはこちらです。
テストが通ればただのserverspecなところが肝心ですね。

chef_and_rabbitmq_spec.rb
require 'spec_helper'

describe command('which chef-solo') do
  it {
    begin
      should return_exit_status(0)
    rescue => e
      puts e.message
      puts "======= Installing Omnibus Chef..."
      cmd = Serverspec::Type::Command.new('curl -L https://www.opscode.com/chef/install.sh | sudo bash')
      expect(cmd.return_exit_status?(0)).to be_true
    end
  }
end

describe package('git') do
  it {
    begin
      should be_installed
    rescue => e
      puts e.message
      puts "======= installing git..."
      cmd = serverspec::type::command.new('apt-get update && apt-get install -y git')
      expect(cmd.return_exit_status?(0)).to be_true
    end
  }
end

describe file('/var/chef/cookbooks/.git') do
  it {
    begin
      should be_directory
    rescue => e
      puts e.message
      puts "======= initializing cookbooks directory..."
      cmd = Serverspec::Type::Command.new('mkdir -p /var/chef/cookbooks')
      expect(cmd.return_exit_status?(0)).to be_true
      cmd = Serverspec::Type::Command.new('git init /var/chef/cookbooks')
      expect(cmd.return_exit_status?(0)).to be_true
      cmd = Serverspec::Type::Command.new('touch /var/chef/cookbooks/.gitkeep')
      expect(cmd.return_exit_status?(0)).to be_true
      cmd = Serverspec::Type::Command.new('cd /var/chef/cookbooks && git add . && git commit .gitkeep -m "empty init"')
      expect(cmd.return_exit_status?(0)).to be_true
    end
  }
end

describe package('rabbitmq-server') do
  it {
    begin
      should be_installed
    rescue => e
      puts e.message
      puts "======= installing rabbitmq by chef..."
      cmd = Serverspec::Type::Command.new('knife cookbook site install rabbitmq')
      expect(cmd.return_exit_status?(0)).to be_true
      cmd = Serverspec::Type::Command.new('chef-solo -o "rabbitmq"')
      expect(cmd.return_exit_status?(0)).to be_true
    end
  }
end

くれぐれもserverspec導入の参考にしないで下さい。

31
31
0

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
31
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?