recipe内にserverspecを書く


# Chef Client 12.1.0 Released

Chef client 12.1.0がリリースされました
https://www.chef.io/blog/2015/03/03/chef-12-1-0-released/
https://github.com/chef/chef/blob/12-stable/RELEASE_NOTES.md
http://docs.chef.io/release_notes.html

packageの複数一括インストールやtemplate/cookbook_file等の事前verifyなど、かゆいところに手が届きそうな変更が色々入ってきていますが、
個人的に一番気になっているのは、"Audit Mode"です。

# Audit Mode
※この機能はchef-client 12.1.0ではExperimentalなので、将来インタフェースや仕様の変更がある可能性があります

Audit Mode。端的に言えば、recipeの中にserverspecを書けるようになります。
例えば、apache2のインストールと80番ポートのチェックのような、従来ならrecipeとserverspecに分かれていた記述を一つのrecipeにまとめて書くことができるようになります。

こんな感じになります。

```ruby
package 'apache2'

control_group "#{cookbook_name}::#{recipe_name}" do
  control "port 80" do
    it "should be open" do
      expect(port(80)).to be_listening
    end
  end
end

```

control_groupのブロック内がserverspec部分です。
control_groupやcontrolなど見慣れない記述が多いですが、上に挙げたドキュメントを参照してください。
このrecipeを--audit-mode enabledオプションをつけたchef-clientコマンドで実行すると、全てのresourceのconvergeが終了した後に、
serverspec部分が実行されます。(audit phase)

```
vagrant@default-ubuntu-1404:~$ sudo chef-client --local-mode -c /tmp/kitchen/client.rb --log_level auto --chef-zero-port 8889 --j /tmp/kitchen/dna.json --audit-mode enabled



[2015-03-04T15:22:31+00:00] WARN: Chef-client has been configured to run audits after it converges. Audit mode is an experimental feature currently under development. API changes may occur. Use at your own risk.
* To enable audit mode after converge, use command line option `--audit-mode enabled` or set `:audit_mode = :enabled` in your config file.
* To disable audit mode, use command line option `--audit-mode disabled` or set `:audit_mode = :disabled` in your config file.
* To only run audit mode, use command line option `--audit-mode audit-only` or set `:audit_mode = :audit_only` in your config file.
Audit mode is disabled by default.
Starting Chef Client, version 12.1.0
[2015-03-04T15:22:38+00:00] WARN: Child with name 'dna.json' found in multiple directories: /tmp/kitchen/dna.json and /tmp/kitchen/dna.json
resolving cookbooks for run list: ["sample::default"]
Synchronizing Cookbooks:
  - sample
Compiling Cookbooks...
Converging 1 resources
Recipe: sample::default
  * apt_package[apache2] action install
    - install version 2.4.7-1ubuntu4 of package apache2
Starting audit phase

sample::default
  port 80
    should be open

Finished in 0.12418 seconds (files took 0.27734 seconds to load)
1 example, 0 failures
Auditing complete

Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 10.170761888 seconds
  1/1 Audits succeeded
  
```

もしport 80が開いていないと

```
Starting audit phase

sample::default
  port 80
    should be open (FAILED - 1)

Failures:

  1) sample::default port 80 should be open
     Failure/Error: expect(port(80)).not_to be_listening
       expected Port "80" not to be listening
```

のようにエラーとなります。

--audit-mode audit_onlyにすると、serverspecのみ実行しconvergeは行いません。
--audit-modeのデフォルトはdisabled（convergeのみ行い、serverspecは実行しない）です。

コマンドラインオプション以外にも、client.rbに

```ruby
audit_mode :audit_only
```

のように書いておくこともできます。

今回はportのチェックのみ行いましたが、serverspecのResourceで定義されているものは何でも使えるようです。

```
# User
  control "vagrant user" do
    it "should be exist" do
      expect(user('vagrant')).to be_exist
    end
  end

# Command
  control "ls command" do
    it "exits with status 0" do
      expect(command('ls').exit_status).to be 0
    end
  end
```

# 使い道

このAudit Modeによって、今まで別々のディレクトリの別々のファイルに書かなくてはいけなかったrecipeとserverspecを、同じrecipeとして書くことができるようになり、recipeのテストが格段に書きやすくなると思われます。

- recipeと対応するserverspecを一つのrecipeファイルにまとめるもよし、
- recipeファイルとserverspecファイルを対にして管理するもよし（recipes/hogehoge.rbとrecipes/hogehoge_test.rb）
- serverspecを書いたrecipeをinclude_recipeして再利用するもよし、
- serverspecだけ書いたcookbookを作り、cookbook間でserverspecを再利用するのもよし、

色々な使い方ができそうな気がします。正式リリースが楽しみです。

# 注意点

使っていて気づいた注意点として、
--audit-mode audit_onlyにしていても、純粋にserverspecのみを実行しているわけではなく、その前にcookbookのcompile phaseは実行されています。
なので、ここで何か処理をやっている場合は注意が必要です。

このaudit modeはchef-soloでは使えませんでした。chef-zero + chef-client local-modeでは使えることを確認しています。