ntpの導入をTDDライクにやってみる

serverspecでテストを実行できるようになったので、ntpの導入をTDDライクに進めながらやってみようと思います。まずはテストケースから。

describe package('ntp') do
  it { should be_installed }
end

describe file('/etc/ntp.conf') do
  it { should be_file }
  its(:content) { should match /server ntp.nict.jp/}
end

describe service('ntpd') do
  it { should be_enabled }
  it { should be_running }
end

実行してみると当然失敗します。

Failed examples:

rspec ./spec/default/base_spec.rb:63 # Package "ntp" should be installed
rspec ./spec/default/base_spec.rb:67 # File "/etc/ntp.conf" should be file
rspec ./spec/default/base_spec.rb:68 # File "/etc/ntp.conf" content should match /server ntp.nict.jp/
rspec ./spec/default/base_spec.rb:72 # Service "ntpd" should be enabled
rspec ./spec/default/base_spec.rb:73 # Service "ntpd" should be running
C:/Ruby193/bin/ruby.exe -S rspec spec/default/base_spec.rb failed

次にレシピですが、きっとopscodeにあると思って検索してみたらやっぱりありました。なのでこちらを使ってみます。まずはBerksfileに追加。

# chef-repo/Berksfile
site :opscode
(中略)
cookbook 'ntp'

で、インストール。

berks install --path cookbooks

これでcookbooksにntpが追加されたので、個別のパラメータを追加しています。設定はattributes/default.rbに行います。serversを追加するのと同期を行うような設定を追加します。serversは公開NTPサーバを2つ追加しておきます。

# default attributes for all platforms
#default['ntp']['servers']   = [] # The default recipe sets a list of common NTP servers (COOK-1170)
default['ntp']['servers']   = ['ntp.nict.jp', 'ntp.jst.mfeed.ad.jp'] # The default recipe sets a list of common NTP servers (COOK-1170)
default['ntp']['peers'] = []
default['ntp']['restrictions'] = []

# internal attributes
(中略)
#default['ntp']['sync_clock'] = false
default['ntp']['sync_clock'] = true

ここまで来て気付いたんですが、タイムゾーンの設定を行わなきゃダメそうです。CentOSの場合、タイムゾーンの設定は/etc/sysconfig/clockを書き換えてやれば良さそうなので、まずは今の状態を確認しておきます。

[vagrant@localhost ~]$ cat /etc/sysconfig/clock 
ZONE="UTC"

で、これを下記のように書き換えるようにして、レシピのtemplates/default/clock.erbとして保存しておきます。

# clock.erb
ZONE="Asia/Tokyo"
UTC="false"

次にrecipes/default.rbをこのファイルを使うように編集します。

file "/etc/localtime" do
  content IO.read("/usr/share/zoneinfo/Asia/Tokyo")
  action :nothing
end

template "/etc/sysconfig/clock" do
  source 'clock.erb'
  owner 'root'
  group 'root'
  mode '0644'
  notifies :create, resources(:file => "/etc/localtime"), :immediately
end
log "done copy to /etc/sysconfig/clock."

clock.erbを書き換えた後に/usr/share/zoneinfo/Asia/Tokyoを/etc/localtimeにコピーするようにしてみました。executeリソース側でacitonが:nothingとなっているのはtemplateリソースから呼ばれたときだけ実行されるようにです。

最後にVagrantfileにntpのレシピを使うように定義します。

  config.vm.provision "chef_solo" do |chef|
    chef.cookbooks_path = ["./chef-repo/cookbooks", "./chef-repo/site-cookbooks"]
    chef.add_recipe "yum"
    chef.add_recipe "rbenv"
    chef.add_recipe "ruby_env"
    chef.add_recipe "nodejs"
    chef.add_recipe "ntp"
  end

これでvagrant provisionを実行します。

vagrant provision

INFO: template[/etc/sysconfig/clock] backed up to /var/chef/backup/etc/sysconfig/clock.chef-20140402081837.835605
INFO: template[/etc/sysconfig/clock] updated file contents /etc/sysconfig/clock
INFO: template[/etc/sysconfig/clock] sending createaction to file[/etc/localtime] (immediate)
INFO: file[/etc/localtime] backed up to /var/chef/backup/etc/localtime.chef-20140402081838.206681
INFO: file[/etc/localtime] updated file contents /etc/localtime
INFO: done copy to /etc/sysconfig/clock.
INFO: package[ntp] installing ntp-4.2.6p5-1.el6.centos from base repository
INFO: cookbook_file[/etc/ntp.leapseconds] created file /etc/ntp.leapseconds
INFO: cookbook_file[/etc/ntp.leapseconds] updated file contents /etc/ntp.leapseconds
INFO: cookbook_file[/etc/ntp.leapseconds] owner changed to 0
INFO: cookbook_file[/etc/ntp.leapseconds] group changed to 0
INFO: cookbook_file[/etc/ntp.leapseconds] mode changed to 644
INFO: template[/etc/ntp.conf] backed up to /var/chef/backup/etc/ntp.conf.chef-20140402171846.501042
INFO: template[/etc/ntp.conf] updated file contents/etc/ntp.conf
INFO: execute[Stop ntpd in preparation for ntpdate]ran successfully
INFO: execute[Stop ntpd in preparation for ntpdate]sending stop action to service[ntpd] (immediate)
INFO: execute[Force sync system clock with ntp server] ran successfully
INFO: service[ntpd] enabled
INFO: service[ntpd] started
INFO: template[/etc/ntp.conf] sending restart action to service[ntpd] (delayed)
INFO: service[ntpd] restarted
INFO: execute[Force sync system clock with ntp server] sending start action to service[ntpd] (delayed)
INFO: Chef Run complete in 60.733069975 seconds
INFO: Running report handlers
INFO: Report handlers complete

templateとファイルコピーが正常に行われ、その後にntpのインストールが動作しているのが分かります。続いてテストの実行ですが、タイムゾーンの設定を追加したのでテストケースも追加しておきます。また公開NTPサーバも2つにしたのでそれのテストも増やします。

describe file('/etc/sysconfig/clock') do
  it { should be_file }
  its(:content) { should match /ZONE="Asia\/Tokyo"/ }
  its(:content) { should match /UTC="false"/ }
end

describe file('/etc/ntp.conf') do
  it { should be_file }
  its(:content) { should match /server ntp.nict.jp/}
  its(:content) { should match /server ntp.jst.mfeed.ad.jp/}
end

うーん、2行になってしまっていますが、この書き方で良いんでしょうか。もうちょっとスマートな方法がありそうですがここはこのまま実行してみます。

rake spec

C:/Ruby193/bin/ruby.exe -S rspec spec/default/base_spec.rb
.........................

Finished in 33.55 seconds
25 examples, 0 failures

無事テストが通ってntpのインストールとタイムゾーンの設定がうまくいったようです。最後に実際に時間が変更されているか確認します。

[vagrant@localhost ~]$ date
Wed Apr  2 22:54:12 JST 2014

おぉ、タイムゾーンも変更されて時間もちゃんと設定されました:-) ただあんまりTDDライクに進められた気がしないので、次はもうちょっとちゃんと進められたらいいなぁ。

参考にさせて頂いたページ