はじめに
インフラ周りのテストにServerspecを使ってますが、よく書くテストの書き方がある程度パターン化してきたので、コピペで使えるサンプルの例文集としてまとめておきます。
この記事の目的は特に機能の網羅性をカバーしようというわけではありません。よくあるユースケースとして、Serverspecでこーゆーのどう書くの?と思ったときのスニペットとしてご利用下さい。
基本
インストール関連
パッケージがインストールされているか確認する
describe package('git') do
it { should be_installed }
end
複数のパッケージがインストールされているかまとめて確認する
%w{autoconf bison flex gcc gcc-c++ kernel-devel make m4}.each do |pkg|
describe package(pkg) do
it { should be_installed }
end
end
指定のバージョンのパッケージがインストールされているか確認する
describe package('td-agent') do
it { should be_installed.with_version('1') }
end
上記はメジャーバージョンだけ指定した場合だけど、細かいバージョンも指定できる。
gemとして指定のバージョンがインストールされているか確認する
describe package('bundler') do
it { should be_installed.by('gem').with_version('1.10.5') }
end
fluentプラグインなど組込gemとしてインストールされているか確認する
plugins = %w(config-expander datacounter numeric-counter zabbix forest)
plugins.each do |plugin|
describe package("fluent-plugin-#{plugin}") do
let(:path) { '/usr/lib64/fluent/ruby/bin:$PATH' }
it { should be_installed.by(:gem) }
end
end
汎用コマンドによる確認
コマンドの標準出力から指定のバージョンがインストールされているか確認する
describe command('ruby -v') do
its(:stdout) { should match /ruby 2\.1\.4/ }
end
コマンドのリターンコードからパスが通っているか確認する
describe command('which mysql') do
its(:exit_status) { should eq 0 }
end
sudoせずコマンドを実行する
describe command('which mysql') do
let(:disable_sudo) { true }
its(:exit_status) { should eq 0 }
end
sudoするユーザを指定する
describe command('which mysql') do
let(:sudo_options) { '-u user01 -i'}
its(:exit_status) { should eq 0 }
end
サービスの起動確認
指定のサービスが起動していて自動起動設定されているか確認する
describe service('elasticsearch') do
it { should be_enabled }
it { should be_running }
end
指定のポートをListenしているか確認する
describe port("9200") do
it { should be_listening }
end
curlでHTTPアクセスして200 OKが返ってくるか確認する
describe command('curl http://127.0.0.1:9200/_plugin/head/ -o /dev/null -w "%{http_code}\n" -s') do
its(:stdout) { should match /^200$/ }
end
ユーザとグループ
グループが存在するか確認する
describe group('ec2-user') do
it { should exist }
end
ユーザが指定のグループに所属しているか確認する
describe user('ec2-user') do
it { should belong_to_group 'ec2-user' }
end
ユーザが指定のUIDを持っているか確認する
describe user('td-agent') do
it { should have_uid 403 }
end
ファイルを確認する
ファイルの中身が指定の文字列にマッチするか確認する
describe file('/etc/sysconfig/clock') do
its(:content) { should match /ZONE="Asia\/Tokyo"/ }
end
ファイルに読み込み権限があるか確認する
%w{
/var/log/httpd/access.log
/var/log/httpd/error.log
}.each do |logfile|
describe file(logfile) do
it { should be_readable.by_user('td-agent') }
end
end
ディレクトリのオーナーとパーミッションを確認する
home_dir = "/home/ec2-user"
describe file("#{home_dir}/.ssh") do
it { should be_directory }
it { should be_owned_by('ec2-user') }
it { should be_grouped_into('ec2-user') }
it { should be_mode '700' }
end
その他
名前解決できるか確認する
zabbix_host = 'zabbix'
describe host(zabbix_host) do
it { should be_resolvable.by('hosts') }
end
応用的なトピック
動的な情報の取得
動的にテスト対象のホスト名を取得する
hostname = host_inventory['hostname']
describe file('/etc/sysconfig/network') do
its(:content) { should match /HOSTNAME=#{hostname}/ }
end
RedHat系かどうか判定する
if os[:family] == 'redhat'
...
else
...
end
elseがない場合は、以下のような書き方もできる
describe yumrepo('epel'), :if => os[:family] == 'redhat' do
it { should exist }
it { should be_enabled }
end
Amazon Linuxかどうか判定する
def os_platform_amazon?
Specinfra.backend.run_command('uname -r').stdout.include?("amzn1")
end
require 'spec_helper'
if os_platform_amazon?
%w{aws-cli s3cmd}.each do |pkg|
describe package(pkg) do
it { should be_installed }
end
end
end
(2015/10/21追記) 現在の最新のserverspecではif os[:family] == 'amazon'
で判定できるようです。これはserverspecの基盤となっているspecinfra(v2.36.0)でos[:family]にamazonが判定できるようなったからで、バージョンの依存関係から対応するserverspec(v2.4.0)以降から使えるはず。
テストケースの共有
複数のサーバ種別で共通するテストケースを使いたい
require 'spec_helper'
shared_examples 'commons' do
describe "commons spec" do
describe package('git') do
it { should be_installed }
end
end
end
base_spec_dir = Pathname.new(File.join(File.dirname(__FILE__)))
Dir[base_spec_dir.join('shared/**/*.rb')].sort.each{ |f| require f }
require 'spec_helper'
describe "app server spec" do
include_examples 'commons'
end
require 'spec_helper'
describe "web server spec" do
include_examples 'commons'
end
テスト対象の制御
テストケースをロール単位で管理したい
以前ブログに書いた以下の記事を参照↓
Serverspecのテストケースをロール単位で管理する
テスト対象のIPとロールを指定する
以前ブログに書いた以下の記事を参照↓
Serverspecでテスト対象のIPとロールを指定する
カスタムマッチャを作りたい
YAMLとしてパース出来るかどうかテストしたい
以前Qiitaに書いた以下の記事を参照↓
serverspecでカスタムマッチャを定義してYAML形式としてパース出来るかどうかをテストするbe_yamlを作ってみる
おわりに
書き出してみたら色々あったけど、何か忘れてるものあったらor新しい小技を覚えたら、随時追記します。