StupidDog's blog

IT関連の手近な所で、疑問に思った事を調べた記録

「Ubuntu14.04 Serverのインフラのテスト自動化(vagrant、serverspec、puppet)」|WEB+DB Press vol.80の特集記事から

はじめに

Rubyのための環境構築を行っているうちにInfrastructure as Codeへ軸が移ってきました。
構築した結果の確認をそろそろ自動化したいと考えているところで、WEB+DB Press vol.80で丁度良く特集が組まれたので、これを参考にしてserverspecの習得も始めました。
ただし、作業環境と対象環境は普段使用している環境で行いました。その結果、いくつかの違いが出たので、それをまとめました。

参考書籍

WEB+DB PRESS Vol.80

WEB+DB PRESS Vol.80

概要

作業環境

Ubuntu14.04 Desktop 64bit
Ruby 1.9.3p484
serverspec 1.7.1
VirtualBox 4.3.12 r93733
Vagrant 1.6.3

Rubyはapt-getによりインストールした場合のバージョンです。

対象環境

Ubuntu14.04 Server 64bit
Puppet 3.6.1

手順
  1. serverspecのインストール
  2. 必要なディレクトリとファイルの作成
  3. テスト駆動インフラの実践(テスト失敗)
  4. プロビジョニング後、再テストの実施(テスト成功)
  5. テスト駆動インフラの繰り返し(Ubuntuでの結果に違いあり)

1.serverspecのインストール

serverspecはgemとして公開されているので、gem installでインストールします。

stupiddog@pc001:~$ sudo gem install serverspec --no-ri --no-rdoc
Fetching: net-ssh-2.9.1.gem (100%)
Fetching: rspec-core-2.14.8.gem (100%)
Fetching: diff-lcs-1.2.5.gem (100%)
Fetching: rspec-expectations-2.14.5.gem (100%)
Fetching: rspec-mocks-2.14.6.gem (100%)
Fetching: rspec-2.14.1.gem (100%)
Fetching: highline-1.6.21.gem (100%)
Fetching: specinfra-1.13.0.gem (100%)
Fetching: serverspec-1.7.0.gem (100%)
Successfully installed net-ssh-2.9.1
Successfully installed rspec-core-2.14.8
Successfully installed diff-lcs-1.2.5
Successfully installed rspec-expectations-2.14.5
Successfully installed rspec-mocks-2.14.6
Successfully installed rspec-2.14.1
Successfully installed highline-1.6.21
Successfully installed specinfra-1.13.0
Successfully installed serverspec-1.7.0
9 gems installed

rubyをユーザローカルとしてインストールしている場合は、sudoは不要です。

2.必要なディレクトリとファイルの作成

参考書籍の特集2第2章のP59を参考にして、ディレクトリとファイルを作成します。
テスト対象となるサーバーOSを、CentOS 6.4 から Ubuntu14.04 Server に変更してるため内容に違いがあります。

作成したディレクトリ
stupiddog@pc001:~/vm$ mkdir test-driven-infra
stupiddog@pc001:~/vm$ cd test-driven-infra/
stupiddog@pc001:~/vm/test-driven-infra$ mkdir modules
stupiddog@pc001:~/vm/test-driven-infra$ mkdir -p roles/app/manifests
stupiddog@pc001:~/vm/test-driven-infra$ tree ~/vm/test-driven-infra/

/home/stupiddog/vm/test-driven-infra/
├── modules
└── roles
    └── app
        └── manifests

4 directories, 0 files
作成したファイル(環境構築部分)
  • /roles/app/manifests/init.pp
class app {}
  • provision.sh
#!/bin/sh

role=$1
puppet apply --modulepath="/vagrant/modules:/vagrant/roles" -e "include $1"
  • Vagrantfile

ベースとするBoxファイルと、最新リリースバージョンのpuppetをインストールするためのコードが特集とは異なります。
Boxファイルは、「Packerを利用したUbuntu14.04 ServerのVagrant用Boxファイルの作成」|ただいまRubyの修行中 - StupidDog's blogで作成したものを使用しています。
puppetのインストール方法については、公式サイトのInstalling Puppet: Debian and Ubuntu — Documentation — Puppet Labsを参考にしています。

# -*- mode: ruby -*-
# vi: set ft=ruby :

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu1404"
  config.vm.box_url = "/home/stupiddog/boxs/ubuntu-14-04-x64-virtualbox.box"

  config.vm.provision :shell, inline: <<-EOF
    wget https://apt.puppetlabs.com/puppetlabs-release-$(lsb_release -cs).deb
    sudo dpkg -i puppetlabs-release-$(lsb_release -cs).deb
    sudo apt-get update
    sudo apt-get -y puppet
  EOF

  config.vm.define :app do |c|
    c.vm.provision :shell do |shell|
      shell.path = "provision.sh"
      shell.args = "app"
    end
  end
end
作成したファイル(テスト部分)

serverspec-initコマンドにより、ひな型を生成してサンプル用の不要なファイルを削除します。

stupiddog@pc001:~/vm/test-driven-infra$ serverspec-init 
Select OS type:

  1) UN*X
  2) Windows

Select number: 1

Select a backend type:

  1) SSH
  2) Exec (local)

Select number: 1

Vagrant instance y/n: y 
Auto-configure Vagrant from Vagrantfile? y/n: y
 + spec/
 + spec/app/
 + spec/app/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
stupiddog@pc001:~/vm/test-driven-infra$ rm spec/app/httpd_spec.rb
ここまでのディレクトリとファイル
stupiddog@pc001:~/vm/test-driven-infra$ tree ~/vm/test-driven-infra/
/home/stupiddog/vm/test-driven-infra/
├── Rakefile
├── Vagrantfile
├── modules
├── provision.sh
├── roles
│   └── app
│       └── manifests
│           └── init.pp
└── spec
    ├── app
    └── spec_helper.rb

6 directories, 5 files
テスト用VMを起動
stupiddog@pc001:~/vm/test-driven-infra$ vagrant up

[実行ログの続き...]

stupiddog@pc001:~/vm/test-driven-infra$ vagrant up
Bringing machine 'app' up with 'virtualbox' provider...
==> app: Importing base box 'ubuntu1404'...
==> app: Matching MAC address for NAT networking...
==> app: Setting the name of the VM: test-driven-infra_app_1401237349890_15840
==> app: Clearing any previously set network interfaces...
==> app: Preparing network interfaces based on configuration...
    app: Adapter 1: nat
==> app: Forwarding ports...
    app: 22 => 2222 (adapter 1)
==> app: Booting VM...
==> app: Waiting for machine to boot. This may take a few minutes...
    app: SSH address: 127.0.0.1:2222
    app: SSH username: vagrant
    app: SSH auth method: private key
    app: Warning: Connection timeout. Retrying...
==> app: Machine booted and ready!
==> app: Checking for guest additions in VM...
==> app: Mounting shared folders...
    app: /vagrant => /home/stupiddog/vm/test-driven-infra
==> app: Running provisioner: shell...
    app: Running: inline script
==> app: stdin: is not a tty
==> app: Selecting previously unselected package puppetlabs-release.
==> app: (Reading database ... 59020 files and directories currently installed.)
==> app: Preparing to unpack puppetlabs-release-trusty.deb ...
==> app: Unpacking puppetlabs-release (1.0-1) ...
==> app: Setting up puppetlabs-release (1.0-1) ...
==> app: Reading package lists...
==> app: Building dependency tree...
==> app: Reading state information...
==> app: The following extra packages will be installed:
==> app:   augeas-lenses debconf-utils facter hiera libaugeas-ruby libaugeas0
==> app:   libruby1.9.1 libyaml-0-2 puppet-common ruby ruby-augeas ruby-json ruby-rgen
==> app:   ruby-shadow ruby1.9.1 virt-what
==> app: Suggested packages:
==> app:   augeas-doc augeas-tools puppet-el vim-puppet ruby-selinux libselinux-ruby1.8
==> app:   librrd-ruby1.9.1 librrd-ruby1.8 ri ruby-dev ruby1.9.1-examples ri1.9.1
==> app:   graphviz ruby1.9.1-dev ruby-switch
==> app: Recommended packages:
==> app:   rdoc
==> app: The following NEW packages will be installed:
==> app:   augeas-lenses debconf-utils facter hiera libaugeas-ruby libaugeas0
==> app:   libruby1.9.1 libyaml-0-2 puppet puppet-common ruby ruby-augeas ruby-json
==> app:   ruby-rgen ruby-shadow ruby1.9.1 virt-what
==> app: 0 upgraded, 17 newly installed, 0 to remove and 12 not upgraded.
==> app: Need to get 4,438 kB of archives.
==> app: After this operation, 21.9 MB of additional disk space will be used.
==> app: Get:1 http://apt.puppetlabs.com/ trusty/main facter amd64 2.0.1-1puppetlabs1 [62.6 kB]
==> app: Get:2 http://us.archive.ubuntu.com/ubuntu/ trusty/main libyaml-0-2 amd64 0.1.4-3ubuntu3 [48.2 kB]
==> app: Get:3 http://apt.puppetlabs.com/ trusty/main hiera all 1.3.3-1puppetlabs1 [12.0 kB]
==> app: Get:4 http://apt.puppetlabs.com/ trusty/main puppet-common all 3.6.1-1puppetlabs1 [1,015 kB]
==> app: Get:5 http://us.archive.ubuntu.com/ubuntu/ trusty/main augeas-lenses all 1.2.0-0ubuntu1 [229 kB]
==> app: Get:6 http://apt.puppetlabs.com/ trusty/main puppet all 3.6.1-1puppetlabs1 [9,322 B]
==> app: Get:7 http://us.archive.ubuntu.com/ubuntu/ trusty/main debconf-utils all 1.5.51ubuntu2 [57.4 kB]
==> app: Get:8 http://us.archive.ubuntu.com/ubuntu/ trusty/main libruby1.9.1 amd64 1.9.3.484-2ubuntu1 [2,667 kB]
==> app: Get:9 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby1.9.1 amd64 1.9.3.484-2ubuntu1 [35.6 kB]
==> app: Get:10 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby all 1:1.9.3.4 [5,334 B]
==> app: Get:11 http://us.archive.ubuntu.com/ubuntu/ trusty/universe virt-what amd64 1.13-1 [13.6 kB]
==> app: Get:12 http://us.archive.ubuntu.com/ubuntu/ trusty/main libaugeas0 amd64 1.2.0-0ubuntu1 [140 kB]
==> app: Get:13 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby-augeas amd64 0.5.0-2 [13.2 kB]
==> app: Get:14 http://us.archive.ubuntu.com/ubuntu/ trusty/universe libaugeas-ruby all 0.5.0-2 [1,394 B]
==> app: Get:15 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby-shadow amd64 2.2.0-1 [11.2 kB]
==> app: Get:16 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby-json amd64 1.8.0-1build1 [49.0 kB]
==> app: Get:17 http://us.archive.ubuntu.com/ubuntu/ trusty/main ruby-rgen all 0.6.6-1 [68.7 kB]
==> app: dpkg-preconfigure: unable to re-open stdin: No such file or directory
==> app: Fetched 4,438 kB in 4min 4s (18.2 kB/s)
==> app: Selecting previously unselected package libyaml-0-2:amd64.
==> app: (Reading database ... 59026 files and directories currently installed.)
==> app: Preparing to unpack .../libyaml-0-2_0.1.4-3ubuntu3_amd64.deb ...
==> app: Unpacking libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
==> app: Selecting previously unselected package augeas-lenses.
==> app: Preparing to unpack .../augeas-lenses_1.2.0-0ubuntu1_all.deb ...
==> app: Unpacking augeas-lenses (1.2.0-0ubuntu1) ...
==> app: Selecting previously unselected package debconf-utils.
==> app: Preparing to unpack .../debconf-utils_1.5.51ubuntu2_all.deb ...
==> app: Unpacking debconf-utils (1.5.51ubuntu2) ...
==> app: Selecting previously unselected package libruby1.9.1.
==> app: Preparing to unpack .../libruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
==> app: Unpacking libruby1.9.1 (1.9.3.484-2ubuntu1) ...
==> app: Selecting previously unselected package ruby1.9.1.
==> app: Preparing to unpack .../ruby1.9.1_1.9.3.484-2ubuntu1_amd64.deb ...
==> app: Unpacking ruby1.9.1 (1.9.3.484-2ubuntu1) ...
==> app: Selecting previously unselected package ruby.
==> app: Preparing to unpack .../ruby_1%3a1.9.3.4_all.deb ...
==> app: Unpacking ruby (1:1.9.3.4) ...
==> app: Selecting previously unselected package virt-what.
==> app: Preparing to unpack .../virt-what_1.13-1_amd64.deb ...
==> app: Unpacking virt-what (1.13-1) ...
==> app: Selecting previously unselected package facter.
==> app: Preparing to unpack .../facter_2.0.1-1puppetlabs1_amd64.deb ...
==> app: Unpacking facter (2.0.1-1puppetlabs1) ...
==> app: Selecting previously unselected package libaugeas0.
==> app: Preparing to unpack .../libaugeas0_1.2.0-0ubuntu1_amd64.deb ...
==> app: Unpacking libaugeas0 (1.2.0-0ubuntu1) ...
==> app: Selecting previously unselected package ruby-augeas.
==> app: Preparing to unpack .../ruby-augeas_0.5.0-2_amd64.deb ...
==> app: Unpacking ruby-augeas (0.5.0-2) ...
==> app: Selecting previously unselected package libaugeas-ruby.
==> app: Preparing to unpack .../libaugeas-ruby_0.5.0-2_all.deb ...
==> app: Unpacking libaugeas-ruby (0.5.0-2) ...
==> app: Selecting previously unselected package ruby-shadow.
==> app: Preparing to unpack .../ruby-shadow_2.2.0-1_amd64.deb ...
==> app: Unpacking ruby-shadow (2.2.0-1) ...
==> app: Selecting previously unselected package ruby-json.
==> app: Preparing to unpack .../ruby-json_1.8.0-1build1_amd64.deb ...
==> app: Unpacking ruby-json (1.8.0-1build1) ...
==> app: Selecting previously unselected package hiera.
==> app: Preparing to unpack .../hiera_1.3.3-1puppetlabs1_all.deb ...
==> app: Unpacking hiera (1.3.3-1puppetlabs1) ...
==> app: Selecting previously unselected package ruby-rgen.
==> app: Preparing to unpack .../ruby-rgen_0.6.6-1_all.deb ...
==> app: Unpacking ruby-rgen (0.6.6-1) ...
==> app: Selecting previously unselected package puppet-common.
==> app: Preparing to unpack .../puppet-common_3.6.1-1puppetlabs1_all.deb ...
==> app: Unpacking puppet-common (3.6.1-1puppetlabs1) ...
==> app: Selecting previously unselected package puppet.
==> app: Preparing to unpack .../puppet_3.6.1-1puppetlabs1_all.deb ...
==> app: Unpacking puppet (3.6.1-1puppetlabs1) ...
==> app: Processing triggers for man-db (2.6.7.1-1) ...
==> app: Processing triggers for ureadahead (0.100.0-16) ...
==> app: ureadahead will be reprofiled on next reboot
==> app: Setting up libyaml-0-2:amd64 (0.1.4-3ubuntu3) ...
==> app: Setting up augeas-lenses (1.2.0-0ubuntu1) ...
==> app: Setting up debconf-utils (1.5.51ubuntu2) ...
==> app: Setting up virt-what (1.13-1) ...
==> app: Setting up libaugeas0 (1.2.0-0ubuntu1) ...
==> app: Setting up ruby (1:1.9.3.4) ...
==> app: Setting up facter (2.0.1-1puppetlabs1) ...
==> app: Setting up ruby-rgen (0.6.6-1) ...
==> app: Setting up ruby1.9.1 (1.9.3.484-2ubuntu1) ...
==> app: Setting up libruby1.9.1 (1.9.3.484-2ubuntu1) ...
==> app: Setting up ruby-augeas (0.5.0-2) ...
==> app: Setting up libaugeas-ruby (0.5.0-2) ...
==> app: Setting up ruby-shadow (2.2.0-1) ...
==> app: Setting up ruby-json (1.8.0-1build1) ...
==> app: Setting up hiera (1.3.3-1puppetlabs1) ...
==> app: Setting up puppet-common (3.6.1-1puppetlabs1) ...
==> app: Setting up puppet (3.6.1-1puppetlabs1) ...
==> app:  * Starting puppet agent
==> app: puppet not configured to start, please edit /etc/default/puppet to enable
==> app:    ...done.
==> app: Processing triggers for libc-bin (2.19-0ubuntu6) ...
==> app: Processing triggers for ureadahead (0.100.0-16) ...
==> app: Running provisioner: shell...
    app: Running: /tmp/vagrant-shell20140528-15607-1gkjyx1.sh
==> app: stdin: is not a tty
==> app: Warning: Setting templatedir is deprecated. See http://links.puppetlabs.com/env-settings-deprecations
==> app:    (at /usr/lib/ruby/vendor_ruby/puppet/settings.rb:1071:in `each')
==> app: Notice: Compiled catalog for ubuntu-1404.vagrantup.com in environment production in 0.02 seconds
==> app: Notice: Finished catalog run in 0.01 seconds

※ 短時間でsudo apt-get updateを繰り返し過ぎるとリポジトリへのアクセスが遅くなるような…気のせいかな。

3.テスト駆動インフラの実践(テスト失敗)

テスト結果を見やすくするための設定ファイルも作成します。

RSpec設定ファイル
--color
--format d
テストコードの作成
  • spec/app/ntp_spec.rb
require 'spec_helper'

describe package('ntp') do
  if { should be_installed }
end
テストを実行
stupiddog@pc001:~/vm/test-driven-infra$ rake spec
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb

Package "ntp"
  should be installed (FAILED - 1)

Failures:

  1) Package "ntp" should be installed
     Failure/Error: it { should be_installed }
       sudo dpkg-query -f '${Status}' -W ntp | grep -E '^(install|hold) ok installed$'
       expected Package "ntp" to be installed
     # ./spec/app/ntp_spec.rb:4:in `block (2 levels) in <top (required)>'

Finished in 3.9 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/app/ntp_spec.rb:4 # Package "ntp" should be installed
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb failed

テストの失敗を確認。チェックに使用しているコマンドも表示されています。

4.プロビジョニング後、再テストの実施(テスト成功)

Puppetマニフェストの作成(ntpモジュール)
  • module/ntp/manifests/init.pp
class ntp {
  package { 'ntp':
    ensure => installed
  }
}
appロールへのモジュール呼び出し追加
class app {
  include ntp
}
Puppetマニフェストの適用
stupiddog@pc001:~/vm/test-driven-infra$ vagrant provision
==> app: Running provisioner: shell...
    app: Running: inline script
==> app: stdin: is not a tty
==> app: (Reading database ... 62069 files and directories currently installed.)
==> app: Preparing to unpack puppetlabs-release-trusty.deb ...
==> app: Unpacking puppetlabs-release (1.0-1) over (1.0-1) ...
==> app: Setting up puppetlabs-release (1.0-1) ...
==> app: Reading package lists...
==> app: Building dependency tree...
==> app: Reading state information...
==> app: puppet is already the newest version.
==> app: 0 upgraded, 0 newly installed, 0 to remove and 22 not upgraded.
==> app: Running provisioner: shell...
    app: Running: /tmp/vagrant-shell20140609-5527-7v3h9v.sh
==> app: stdin: is not a tty
==> app: Warning: Setting templatedir is deprecated. See http://links.puppetlabs.com/env-settings-deprecations
==> app:    (at /usr/lib/ruby/vendor_ruby/puppet/settings.rb:1071:in `each')
==> app: Notice: Compiled catalog for ubuntu-1404.vagrantup.com in environment production in 0.19 seconds
==> app: Notice: /Stage[main]/Ntp/Package[ntp]/ensure: ensure changed 'purged' to 'present'
==> app: Notice: Finished catalog run in 12.68 seconds
テストの実行
stupiddog@pc001:~/vm/test-driven-infra$ rake spec
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb

Package "ntp"
  should be installed

Finished in 3.96 seconds
1 example, 0 failures

テストの成功を確認。これで、テスト駆動インフラの入り口に着ました。

5.テスト駆動インフラの繰り返し(Ubuntuでの結果に違いあり)

テストの追加

ntpdサービスが自動起動するようになっている(be_enabled)と、起動している(be_running)をテストするコードを追加する。

  • spec/app/ntp_spec.rb
require 'spec_helper'

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

describe service('ntpd') do
  it { should be_enabled }
  it { should be_running }
end
テストの実施(テスト失敗)
stupiddog@pc001:~/vm/test-driven-infra$ rake spec
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb

Package "ntp"
  should be installed

Service "ntpd"
  should be enabled (FAILED - 1)
  should be running

Failures:

  1) Service "ntpd" should be enabled
     Failure/Error: it { should be_enabled }
       sudo ls /etc/rc3.d/ | grep -- '^S..ntpd' || sudo grep 'start on' /etc/init/ntpd.conf
       expected Service "ntpd" to be enabled
     # ./spec/app/ntp_spec.rb:8:in `block (2 levels) in <top (required)>'

Finished in 4.06 seconds
3 examples, 1 failure

Failed examples:

rspec ./spec/app/ntp_spec.rb:8 # Service "ntpd" should be enabled
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb failed

新しく追加したテストの失敗を確認。
ここで、テスト結果を見ると書籍と異なることが分かります。
失敗しているのは、「ntpdサービスが自動起動するようになっている(be_enabled)」のみで、「起動している(be_running)」は成功しています。

これは、Ubuntuのaptでntpをインストールした場合、自動起動の設定も合わせて行われるためです。
念のためテスト対象の仮想環境でntpサービスが起動していることを確認します。

stupiddog@pc001:~/vm/test-driven-infra$ vagrant ssh
Welcome to Ubuntu 14.04 LTS (GNU/Linux 3.13.0-24-generic x86_64)

 * Documentation:  https://help.ubuntu.com/
Last login: Mon May 19 10:27:04 2014 from 10.0.2.2

vagrant@ubuntu-1404:~$ ps aux | grep ntpd | grep -v grep
ntp       2026  0.0  0.2  31444  2056 ?        Ss   07:11   0:00 /usr/sbin/ntpd -p /var/run/ntpd.pid -g -u 105:113
vagrant@ubuntu-1404:~$ 

ntpサービス(ntpd)が起動しています。
では何故「ntpdサービスが自動起動するようになっている(be_enabled)」が失敗となったのか。
もう一度、テスト結果を確認すると失敗しているテストのコマンドが出力されていることが分かります。

  1) Service "ntpd" should be enabled
     Failure/Error: it { should be_enabled }
       sudo ls /etc/rc3.d/ | grep -- '^S..ntpd' || sudo grep 'start on' /etc/init/ntpd.conf
       expected Service "ntpd" to be enabled
     # ./spec/app/ntp_spec.rb:8:in `block (2 levels) in <top (required)>'

二種類のコマンドのどちらかが成功した場合にテスト成功となるようです。

  • sudo ls /etc/rc3.d/ | grep -- '^S..ntpd'
  • sudo grep 'start on' /etc/init/ntpd.conf

まず、コマンドを手入力してみます。

vagrant@ubuntu-1404:~$ sudo ls /etc/rc3.d/ | grep -- '^S..ntpd'
vagrant@ubuntu-1404:~$ sudo ls /etc/rc3.d/
README	S20rsync  S20virtualbox-guest-utils  S21puppet	S23ntp	S70dns-clean  S70pppd-dns  S99grub-common  S99ondemand	S99rc.local

vagrant@ubuntu-1404:~$ sudo grep 'start on' /etc/init/ntpd.conf
grep: /etc/init/ntpd.conf: No such file or directory

結果から、/etc/init/ntpd.confファイルは存在しないようです。
そこでもう一つのコマンドを確認すると、起動スクリプトの有無をチェックしていることが分かります。
しかし、実際に存在しているntpの起動スクリプト名が「S23ntpd」ではなく「S23ntp」なので条件に一致しません。

結果の考察と対応

serverspecでのテストで、成功となるケースが失敗となってしまいました。
ntpサービスがファイル配置や名前を頻繁に変えてしまうのが原因だと思います。
これで、serverspecを使用しない~ではなく、OSSでありインフラテストの仕組みを提供しているのだから自分の環境で正しいテストが出来るようにテストコードを書き直します。

どうやってコマンドが生成されているか

テストが失敗した場合に、テストに使用しているコマンドが出力されるので敢えて存在しないサービス名を指定してみました。

  • spec/app/ntp_spec.rb
stupiddog@pc001:~/vm/test-driven-infra$ cat spec/app/ntp_spec.rb
require 'spec_helper'

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

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

stupiddog@pc001:~/vm/test-driven-infra$ rake spec
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb

Package "ntp"
  should be installed

Service "aaa"
  should be enabled (FAILED - 1)
  should be running (FAILED - 2)

Failures:

  1) Service "aaa" should be enabled
     Failure/Error: it { should be_enabled }
       sudo ls /etc/rc3.d/ | grep -- '^S..aaa' || sudo grep 'start on' /etc/init/aaa.conf
       expected Service "aaa" to be enabled
     # ./spec/app/ntp_spec.rb:8:in `block (2 levels) in <top (required)>'

  2) Service "aaa" should be running
     Failure/Error: it { should be_running }
       sudo ps aux | grep -w -- aaa | grep -qv grep
       expected Service "aaa" to be running
     # ./spec/app/ntp_spec.rb:9:in `block (2 levels) in <top (required)>'

Finished in 4.02 seconds
3 examples, 2 failures

Failed examples:

rspec ./spec/app/ntp_spec.rb:8 # Service "aaa" should be enabled
rspec ./spec/app/ntp_spec.rb:9 # Service "aaa" should be running
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb failed

describe service()に指定した名前が、そのまま使用されるようです。
そこで、テストコードを次のように書き直してテストが正常に行われるようにしました。

  • spec/app/ntp_spec.rb
require 'spec_helper'

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

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

describe service('ntpd') do
  it { should be_running }
end
テストの実施
stupiddog@pc001:~/vm/test-driven-infra$ rake spec
/usr/bin/ruby1.9.1 -S rspec spec/app/ntp_spec.rb

Package "ntp"
  should be installed

Service "ntp"
  should be enabled

Service "ntpd"
  should be running

Finished in 4.02 seconds
3 examples, 0 failures

これで対象環境のテストコードと、ntpサービスを導入したUbuntu14.04 Server環境を作るためのコードが作成できました。

まとめ

今回、テストコードを変更してテストを通す結果となりました。
テストが成功するようにテストコードを変更したことになりますが、手本とした書籍のコードがたまたま存在していただけです。
ゼロから構築することを考えた場合、serverspecでの記述方法だけでなく、どうやってチェックしているかを知らないと新しい要素のテストコードを記述できないことが分かりました。
実施してみて注意することが分かったので、今後は他の条件のテストも行って習得度を上げていきます。