【Serverspec】構築したサーバはServerspecを使ってテストしよう
AnsibleやChefといった、プロビジョニングツールを用いてサーバ環境を構築したので、次はServerspecを使ってちゃんとインストールされているか等、テストをしないとなということで、Serverspecの紹介です。
Serverspecとは
サーバ向けのテストフレームワークで、Rubyで実装されており、Rubyのテストフレームワーク「RSpec」の書き方でテストが書ける。
しかし、Serverspecの真の目的は、インフラストラクチャコードのリファクタリング支援すること。
インストール
*Rubyが既にインストールされていることが前提
$ gem install serverspec
or
- Gemfile
gem 'serverspec'
$ bundle install
初期設定
$ serverspec-init Select OS type: 1) UN*X 2) Windows Select number: 1 Select a backend type: 1) SSH 2) Exec (local) Select number: 1 Vagrant instance y/n: n Input target host name: www.example.jp + spec/ + spec/default/ + spec/default/sample_spec.rb + spec/spec_helper.rb + Rakefile + .rspec
- OSの種類を聞かれるので、テスト対象のOSの番号を入力する
- バックエンドの種類を聞かれるので、テスト対象はSSH接続する必要があるなら1、ローカルに対して行う場合は2を入力する
- Vagrantインスタンスに対して行うかどうかを聞かれる
Rakefile
生成されたRakefileは以下のようになっている
require 'rake' require 'rspec/core/rake_task' task :spec => 'spec:all' task :default => :spec namespace :spec do targets = [] Dir.glob('./spec/*').each do |dir| next unless File.directory?(dir) target = File.basename(dir) target = "_#{target}" if target == "default" targets << target end task :all => targets task :default => :all targets.each do |target| original_target = target == "_default" ? target[1..-1] : target desc "Run serverspec tests to #{original_target}" RSpec::Core::RakeTask.new(target.to_sym) do |t| ENV['TARGET_HOST'] = original_target t.pattern = "spec/#{original_target}/*_spec.rb" end end end
spec以下のディレクトリをホスト名として使用している
環境変数にtarget hostnameをセットしているので、key名 'TARGET_HOST'
は空けておいた方が無難か...
spec_helper.rb
localhostの場合
require 'serverspec' set :backend, :exec
たったこれだけ
SSHの場合
require 'serverspec' require 'net/ssh' set :backend, :ssh if ENV['ASK_SUDO_PASSWORD'] begin require 'highline/import' rescue LoadError fail "highline is not available. Try installing it." end set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false } else set :sudo_password, ENV['SUDO_PASSWORD'] end host = ENV['TARGET_HOST'] options = Net::SSH::Config.for(host) options[:user] ||= Etc.getlogin set :host, options[:host_name] || host set :ssh_options, options # Disable sudo # set :disable_sudo, true # Set environment variables # set :env, :LANG => 'C', :LC_MESSAGES => 'C' # Set PATH # set :path, '/sbin:/usr/local/sbin:$PATH'
注意点
Root以外のユーザで実行する場合、環境変数 'SUDO_PASSWORD'
にパスワードをセットする必要がある
$ SUDO_PASSWORD=xxxxxxxx rake spec
パスワード入力プロンプトを立ち上げて入力する場合
$ ASK_SUDO_PASSWORD=1 rake spec
※ 別途highlineをインストールする必要がある
Vagrant
require 'serverspec' require 'net/ssh' require 'tempfile' set :backend, :ssh if ENV['ASK_SUDO_PASSWORD'] begin require 'highline/import' rescue LoadError fail "highline is not available. Try installing it." end set :sudo_password, ask("Enter sudo password: ") { |q| q.echo = false } else set :sudo_password, ENV['SUDO_PASSWORD'] end host = ENV['TARGET_HOST'] `vagrant up #{host}` config = Tempfile.new('', Dir.tmpdir) config.write(`vagrant ssh-config #{host}`) config.close options = Net::SSH::Config.for(host, [config.path]) options[:user] ||= Etc.getlogin set :host, options[:host_name] || host set :ssh_options, options # Disable sudo # set :disable_sudo, true # Set environment variables # set :env, :LANG => 'C', :LC_MESSAGES => 'C' # Set PATH # set :path, '/sbin:/usr/local/sbin:$PATH'
パスワード周りは普通のSSHと同じ。
タスク内で vagrant up
を実行している。
vagrant ssh-config
を内部で実行し、ssh情報をTempfileに保管している。
テスト実行
rakeコマンドで実行。
$ rake spec
$ rake -vT rake spec:_default # Run serverspec tests to default rake spec:localhost # Run serverspec tests to localhost
Support OS
マルチサポートで一応テストもしているっぽい
- AIX
aix
- Arch Linux
arch
- Darwin(Mac OS X)
darwin
- Debian
debian
- Fedora/Red Hat/CentOS
fedora
,redhat
- FreeBSD
freebsd
- Gentoo Linux
gentoo
- NixOS
nixos
- OpenBSD
openbsd
- openSUSE
opensuse
- Plamo Linux
plamo
- SmartOS
smartos
- Solaris
solaris
- SUSE
suse
- Ubuntu
ubuntu
- Windows
windows
明示的にOSを指定する場合は以下のように記述する
require 'serverspec' set :os, :family => 'redhat', :release => '7', :arch => 'x86_64'
Resource Types
package
パッケージがインストールされているかどうかのテスト
describe package('httpd') do it { should be_installed } end
service
サービスに関するテスト
describe service('htpd') do it { should be_enabled } #自動起動が有効になっているか it { should be_running } #起動しているか end
port
ポートに関するテスト
describe port(80) do it { should be_listening } end
file
ファイルに関するテスト
#ファイルが存在するか describe file('/etc/passwd') do it { should be_file } end # ディレクトリが存在するか describe file('/var/log/httpd') do it { should be_directory } end
command
コマンド実行した出力結果に対してのテスト
describe command('ls -al /') do its(:stdout) { should match /bin/ } end describe command('ls /foo') do its(:stderr) { should match /No such file or directory/ } end describe command('ls /foo') do its(:exit_status) { should eq 0 } end