Chef のレシピから serverspec のテストを自動生成する chef-serverspec-handler という gem を作ってみた

『Chef のレシピは「こうあるべき」を記述するものだから、レシピからテストが自動生成できるべきだよな』とずっと思っていたんだけど、最近触りはじめた serverspec がシンプルで簡単に自動生成できそうなのでやってみた。

使い方は上記リンクに書いてある通りなのですが、たとえば Chef のレシピにこう書いてあるやつを、

template '/var/tmp/template.txt' do
  source 'template.txt.erb'
  mode 0777
  owner 'root'
  group 'root'
  variables(:val1 => 'val1', :val2 => 'val2', :val3 => 'val3')
  action :create
end

このような serverspec のテストに自動変換してくれます。

context file('/var/tmp/template.txt') do
  it {
    should be_file
    should be_mode 777
    should be_owned_by 'root'
    should contain 'val1'
    should contain 'val2'
    should contain 'val3'
  }
end

(もっと詳しくは 入力例出力例 を参照。)

この形がよいのかどうかはよく分からないけど Chef の Handler として実装してあり、--why-run オプションと組み合わせて使うことを想定しています。

コンセプトコードみたいなものなので、ちゃんと動かないところがたくさんあるかも。というか試しに Opscode コミュニティの wordpress クックブック + ニフティクラウドの CentOS 6.3 64bit Plain サーバーで試したら、自動生成された 77 テスト中 4 つのテストが失敗した。

Failures:                                                                                                                                                                  [18/829]

  1) apache2::default Package "apache2" 
     Failure/Error: it { should be_installed }
       rpm -q apache2
       パッケージ apache2 はインストールされていません。
       expected Package "apache2" to be installed
     # ./spec/localhost/apache2/default_spec.rb:5:in `block (3 levels) in <top (required)>'

  2) apache2::mod_php5 Package "php package" 
     Failure/Error: it { should be_installed }
       rpm -q php\ package
       パッケージ php package はインストールされていません。
       expected Package "php package" to be installed
     # ./spec/localhost/apache2/mod_php5_spec.rb:9:in `block (3 levels) in <top (required)>'

  3) mysql::server File "/etc/my.cnf" 
     Failure/Error: should contain 'false'
       grep -q -- false /etc/my.cnf
       expected File "/etc/my.cnf" to contain "false"
     # ./spec/localhost/mysql/server_spec.rb:73:in `block (3 levels) in <top (required)>'

  4) wordpress::default File "/etc/httpd/sites-available/wordpress.conf" 
     Failure/Error: should contain '{:template=>"wordpress.conf.erb", :enable=>true, :docroot=>"/var/www/wordpress", :server_name=>"localhost", :server_aliases=>["localhost"], :na
me=>"wordpress"}'
       grep -q -- \{:template\=\>\"wordpress.conf.erb\",\ :enable\=\>true,\ :docroot\=\>\"/var/www/wordpress\",\ :server_name\=\>\"localhost\",\ :server_aliases\=\>\[\"localhost\"
\],\ :name\=\>\"wordpress\"\} /etc/httpd/sites-available/wordpress.conf
       expected File "/etc/httpd/sites-available/wordpress.conf" to contain "{:template=>\"wordpress.conf.erb\", :enable=>true, :docroot=>\"/var/www/wordpress\", :server_name=>\"l
ocalhost\", :server_aliases=>[\"localhost\"], :name=>\"wordpress\"}"
     # ./spec/localhost/wordpress/default_spec.rb:44:in `block (3 levels) in <top (required)>'

1,2 は CentOS なのに Debian/Ubuntu のパッケージをインストールしようとしているのでレシピが悪いように思うのですが、
3,4 は chef-serverspec-handler が template リソースの variables で指定されたハッシュの値を単純に should contain しているのがダメで、そもそも variables は単純な値の埋め込み以外にも true/false を渡してテンプレートの内容を切り分けるような用途にも使うので、テンプレートの内容を論理的に解析する必要があり、対応するのがむずかしそうに思った。

というようにマダマダな感じなのですが、既存のレシピ資産にテストを書く足がかりにはなると思うので、よかったらお試しください。