FLINTERS Engineer's Blog

FLINTERSのエンジニアによる技術ブログ

Chefテスト始めました!

こんにちは、貴子です。
インフラチームでchefのテストを導入して、運用フローまで落とせてきたので
何が問題でどう改善したかをまとめました。

テストを導入する前の問題点

テストを始める前のrecipeにはたくさんの問題がありました。
* bash・executeを多様している
* ダブルコーテーションとシングルコーテーションの使い分けができていない
* recipe通りに動いているか確認が漏れがある
* CentOSだと動くけれどAmazon linuxだと動かない
..etc

これらの問題は2つに分類することが出来ました。
1. コードの書き方に統一されていない
2. 動作チェックが甘い

改善へ

1.コーディングスタイルを統一させる
Foodcritic・ Rubocopを利用して構文チェックをするようになりました。
Foodcritic (http://acrmp.github.io/foodcritic/) はchefの構文のチェックをしてくれるツールです。
実際に使用してみます。
(1). まずはchef-repositoryにテストに必要なもののGemfileを作成します

vim Gemfile
# Gemfile
source 'https://rubygems.org'
 
gem 'test-kitchen'
gem 'kitchen-ec2'
gem 'kitchen-vagrant'
gem 'serverspec'
gem 'foodcritic'
gem 'rubocop'

(2). vendor/bundle配下にgemインストールします

bundle install --path vendor/bundle 

(3). stashへvendor/bundle配下のものはプッシュしたくないので、無視をするように.gitignoreに記述をします。

vim .gitignore
# .gitignore
vendor/bundle 

準備ができたので、Foodcriticを実行します

bundle exec foodcritic .

f:id:t_onoue:20150813151704p:plain エラーが出ました。
指摘部分を確認します。

directory "/etc/skel/Maildir/new" do
  mode '0700'
  recursive true
end
directory "/etc/skel/Maildir/cur" do
  mode '0700'
  recursive true
end
directory "/etc/skel/Maildir/tmp" do
  mode '0700'
  recursive true
end

FC005のエラーと照らし合わせると、配列を使わずディレクトリを作成していたことが原因でした。

#修正後のコード
%w(new cur tmp).each do |dir|
  directory "/etc/skel/Maildir/#{dir}" do
    mode '0700'
    recursive true
  end
end

指摘通りに書きなおして再度foodcriticをかけるとエラーはでなくなりました。
次はRubocop実行してrubyの構文チェックをします。

bundle exec rubocop recipes

f:id:t_onoue:20150814105514p:plain Criticalを示すCがでて42行目に空白があるのがよくないよーと言われました。
f:id:t_onoue:20150813181948p:plain 確認すると確かに最終行に無駄な改行が入っています。
削除して再度実行すると通りました。
rubocopはそれぐらい良えやんと言いたくなるところまで、ビシッと指摘してくれるとても良い子です。
きっと、それぐらい良えやんという怠惰が醜いコードを生むのです。

2. 動作チェックのテスト自動化
serverspecでテストを書いて、test-Kitchenで実行して動作保証をします。
serverspec ( http://serverspec.org/ )とは、サーバの状態をテストするためのフレームワークです。
まずは、テストファイルを置くdirectoryを作成します。

mkdir -p test/integration/default/serverspec/

テストを書きます。
基本的にはrecipeに書いたことを、そのままテストをします。
上のrecipeではdirectoryを作成して権限を変更したので、
ディレクトリが作成されていて、権限が0700になっていることを確認します。

vim  test/integration/default/serverspec/default_spec.rb
# new cur tmpのdirectory作成確認と権限確認
%w(new cur tmp).each do |dir|
  describe file("/etc/skel/Maildir/#{dir}") do
    it { should be_directory }
    it { should be_mode 700 }
  end
end

test-Kitchenの実行環境を整えます。
test-Kitchen ( http://kitchen.ci/ )とはクラウド上にテスト用のInstanceを立てて、recipe ~ testまで実行して確認できるツールです。

kitchen init

kitchen.ymlを書き換えます。 (※kitchen.ymlは自分の環境に合わせて書き換えてください。)

vim .kitchen.yml
# .kitchen.yml
driver:
  name: ec2
  availability_zone: b
  aws_access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
  aws_secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
  aws_ssh_key_id: '秘密鍵名'
  instance_type: 't2.small'
  security_group_ids: ['*subnet_id']
  image_id: 'ami-cbf90ecb'
  region: <%= ENV['AWS_REGION'] %>
  subnet_id: 'subnet_id'
  associate_public_ip: true
  interface: private
  user_data: "#!/bin/bash\necho 'Defaults !requiretty' >> /etc/sudoers.d/cloud-init"
transport:
  ssh_key: 秘密鍵名
  connection_timeout: 10
  connection_retries: 5
  username: ec2-user
provisioner:
  name: chef_solo
platforms:
  - name: amazonlinux
suites:
  - name: defaults
    run_list:
      - recipe[base::default]
    attributes:

test-Kitchenを実行します。

# テストサーバー構築
bundle exec kitchen create
# recipe実行
bundle exec kitchen converge
# テスト(serverspec)実行
bundle exec kitchen verify 
# テストサーバー削除
bundle exec kitchen destroy

kitchen verify を叩いて上手くいったら、テスト完了なのでテストサーバーを潰します。

これで「コードの書き方に統一されていない・動作チェックが甘い 」という問題点を解決できました。
継続的に続けていくために、運用フローに落とします。

改善後の運用フロー

f:id:t_onoue:20150813143050p:plain

これで動作保証がされた品質の良いrecipeを書いていくことができます。
慣れるまでとても大変でしたが、一度身につけてしまえば、とても楽しくテスト実行までをやれるようになりました。
しかし、やはり好き勝手に書いて提供していた時の方がスピードは早く、
今後はいかに早く品質が良い物を提供していけるかに取り組んでいきたいです。
そもそもテストを一回で通れば時間はかなり節約できると思うので、
綺麗なrecipeがかけるエンジニアになれるよう精進します。