serverspecを試してみる

今回はserverspecを簡単に触ってみました。

インストール


まずはrubyをインストールします。
独立した環境を作りたい為、特定のユーザホームディレクトリ配置したrubyの環境を作ります。

$ cd /usr/local/src
$ wget ftp://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p195.tar.gz
$ tar -xvf ruby-2.0.0-p195.tar.gz 
$ cd ruby-2.0.0-p195
$ ./configure --prefix=/home/myuser/ruby --enable-shared
$ make
$ make install

$ PATH=$PATH:/home/myuser/ruby/bin
$ export PATH


serverspecを導入します。gemだけで入ります。

$ /home/myuser/ruby/bin/gem install serverspec
Fetching: net-ssh-2.6.7.gem (100%)
Successfully installed net-ssh-2.6.7
Fetching: rspec-core-2.13.1.gem (100%)
Successfully installed rspec-core-2.13.1
Fetching: diff-lcs-1.2.4.gem (100%)
Successfully installed diff-lcs-1.2.4
Fetching: rspec-expectations-2.13.0.gem (100%)
Successfully installed rspec-expectations-2.13.0
Fetching: rspec-mocks-2.13.1.gem (100%)
Successfully installed rspec-mocks-2.13.1
Fetching: rspec-2.13.0.gem (100%)
Successfully installed rspec-2.13.0
Fetching: highline-1.6.19.gem (100%)
Successfully installed highline-1.6.19
Fetching: serverspec-0.6.2.gem (100%)
Successfully installed serverspec-0.6.2
Parsing documentation for net-ssh-2.6.7
Installing ri documentation for net-ssh-2.6.7
Parsing documentation for rspec-core-2.13.1
Installing ri documentation for rspec-core-2.13.1
Parsing documentation for diff-lcs-1.2.4
Installing ri documentation for diff-lcs-1.2.4
Parsing documentation for rspec-expectations-2.13.0
Installing ri documentation for rspec-expectations-2.13.0
Parsing documentation for rspec-mocks-2.13.1
Installing ri documentation for rspec-mocks-2.13.1
Parsing documentation for rspec-2.13.0
Installing ri documentation for rspec-2.13.0
Parsing documentation for highline-1.6.19
Installing ri documentation for highline-1.6.19
Parsing documentation for serverspec-0.6.2
Installing ri documentation for serverspec-0.6.2
8 gems installed


初期化します。今回はローカル実行にします。

$ /home/myuser/ruby/bin/serverspec-init 
Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 2

 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile


これで準備が出来ました。

使ってみる


テストケースを書いてみました。内訳は以下の通りです。

  • SELinuxは無効になっている
  • ntpdが起動しており、ntp.nict.jp、ntp.jst.mfeed.ad.jp、ntp.nc.u-tokyo.ac.jpを参照先とする
  • 「myuser」というユーザのチェック
  • 「/etc/sudoers」のファイルチェック


内容は以下の通りです。

require 'spec_helper'

# SELinux
describe selinux do
  it { should be_disabled }
end

describe command('sestatus') do
  it { should return_stdout 'SELinux status:                 disabled' }
end

describe file('/etc/selinux/config') do
  it { should contain 'SELINUX=disabled' }
end

# ntpd
describe service('ntpd') do
  it { should be_enabled }
end

describe service('ntpd') do
  it { should be_running }
end

describe file('/etc/ntp.conf') do
  it { should contain 'server ntp.nict.jp' }
end

describe file('/etc/ntp.conf') do
  it { should contain 'server ntp.jst.mfeed.ad.jp' }
end

describe file('/etc/ntp.conf') do
  it { should contain 'server ntp.nc.u-tokyo.ac.jp' }
end

# User
describe user('myuser') do
  it { should exist }
end

describe user('myuser') do
  it { should belong_to_group 'myuser' }
end

describe user('myuser') do
  it { should have_uid 2000 }
end

describe group('myuser') do
  it { should exist }
end

group('myuser') do
  it { should have_gid 2000 }
end

describe user('myuser') do
  it { should have_home_directory '/home/myuser' }
end

describe user('myuser') do
  it { should have_login_shell '/bin/bash' }
end

# File
describe file('/etc/sudoers') do
  it { should be_file }
end

describe file('/etc/sudoers') do
  it { should be_mode 440 }
end

describe file('/etc/sudoers') do
  it { should be_owned_by 'root' }
end

describe file('/etc/sudoers') do
  it { should be_grouped_into 'root' }
end


実行してみます。

# rake spec
(in /home/myuser/test)
/home/myuser/ruby/bin/ruby -S rspec spec/localhost/linux_spec.rb
........Fid: myuser: No such user
Fid: myuser: No such user
FFFF....

Failures:

  1) User "myuser" 
     Failure/Error: it { should exist }
       id myuser
       id: myuser: No such user
     # ./spec/localhost/linux_spec.rb:39:in `block (2 levels) in <top (required)>'

  2) User "myuser" 
     Failure/Error: it { should belong_to_group 'myuser' }
       id myuser | awk '{print $3}' | grep -- myuser
     # ./spec/localhost/linux_spec.rb:43:in `block (2 levels) in <top (required)>'

  3) User "myuser" 
     Failure/Error: it { should have_uid 2000 }
       id myuser | grep -- \^uid\=2000\(
     # ./spec/localhost/linux_spec.rb:47:in `block (2 levels) in <top (required)>'

  4) Group "myuser" 
     Failure/Error: it { should exist }
       getent group | grep -wq -- myuser
     # ./spec/localhost/linux_spec.rb:51:in `block (2 levels) in <top (required)>'

  5) User "myuser" 
     Failure/Error: it { should have_home_directory '/home/myuser' }
       getent passwd myuser | cut -f 6 -d ':' | grep -w -- /home/myuser
     # ./spec/localhost/linux_spec.rb:59:in `block (2 levels) in <top (required)>'

  6) User "myuser" 
     Failure/Error: it { should have_login_shell '/bin/bash' }
       getent passwd myuser | cut -f 7 -d ':' | grep -w -- /bin/bash
     # ./spec/localhost/linux_spec.rb:63:in `block (2 levels) in <top (required)>'

Finished in 0.16055 seconds
18 examples, 6 failures

Failed examples:

rspec ./spec/localhost/linux_spec.rb:39 # User "myuser" 
rspec ./spec/localhost/linux_spec.rb:43 # User "myuser" 
rspec ./spec/localhost/linux_spec.rb:47 # User "myuser" 
rspec ./spec/localhost/linux_spec.rb:51 # Group "myuser" 
rspec ./spec/localhost/linux_spec.rb:59 # User "myuser" 
rspec ./spec/localhost/linux_spec.rb:63 # User "myuser" 
rake aborted!
/home/myuser/ruby/bin/ruby -S rspec spec/localhost/linux_spec.rb failed


「myuser」というユーザが存在しなかったため、これに関係するテストケースが失敗しました。
ということで、ユーザを作成します。

# groupadd -g 2000 myuser
# useradd -g 2000 -u 2000 -s /bin/bash -d /home/myuser myuser


もう一度実行すると、テストケースが全て通り、問題が解消された事が確認出来ました。

# rake spec
(in /home/myuser/test)
/home/myuser/ruby/bin/ruby -S rspec spec/localhost/linux_spec.rb
..................

Finished in 0.15403 seconds
18 examples, 0 failures


分かりやすい事もあり、テストケースを増やして環境構築時の品質向上を考えてみようと思います。


今日はこんなところで。