Macのbashビルトインコマンドのtimeと/usr/bin/timeは別物
はじめに
あるコマンドの時間計測やリソース使用量を表示する time と言うコマンドがあります。
このコマンドを使い実行時のメモリー使用量を測ろうかと思ったところで問題が発生しました。
問題
Macでtimeコマンドを使おうとすると bashビルトインのコマンドが呼び出されてしまいリソース使用量は取得できないので、別途インストールが必要なのだと思って GNU timeを Homebrewでインストールしたが以下のバグが残ったままでした。
GNU Time にある壮大なバグ - Qiita
対応
そこで調べてみると bashビルトイン以外に timeコマンドがあることが分かりました。
/usr/bin/timeならばリソース使用量も表示できます。
$ type -a time time is a shell keyword time is /usr/bin/time
bashビルトインコマンドのヘルプはhelp
$ help time time: time [-p] PIPELINE Execute PIPELINE and print a summary of the real time, user CPU time, and system CPU time spent executing PIPELINE when it terminates. The return status is the return status of PIPELINE. The `-p' option prints the timing summary in a slightly different format. This uses the value of the TIMEFORMAT variable as the output format. times: times Print the accumulated user and system times for processes run from the shell.
ビルトインではない timeコマンドのヘルプはmanコマンドで確認できます。
BSD系の timeコマンドがベースなのは分かります。
(分岐したOS毎に出力やオプションが変化しているので確認が必要)
TIME(1) BSD General Commands Manual TIME(1) NAME time -- time command execution SYNOPSIS time [-lp] utility DESCRIPTION ...
確認
GNU timeでバグの確認方法で使用されていたコマンドにより、目的のメモリー使用量を測れることが確認できました。
maximum resident set sizeの値がバイト単位で出力されている。
$ /usr/bin/time -l perl -e '"X" x 400 x 1024 x 1024' 0.27 real 0.12 user 0.14 sys 421330944 maximum resident set size 0 average shared memory size 0 average unshared data size 0 average unshared stack size 103186 page reclaims 0 page faults 0 swaps 0 block input operations 0 block output operations 0 messages sent 0 messages received 0 signals received 0 voluntary context switches 315 involuntary context switches
おまけ
GNU timeの壮大なバグについては、各配布先環境でパッチが当てられています。
このmaximum resident set sizeが曲者で、この値の元はシステムコールのgetrusage(2)のru_maxrssの値から算出しています。
しかし、OS毎にru_maxrssの単位が変わります。
manコマンドで確認したところ
OS | 単位 |
OS X 10.11.3 | バイト |
FreeBSD 11.0 | キロバイト |
Linux 2.6.32~ | キロバイト |
そして元のコードでは、ページ単位として処理されている。
「(ru_maxrss * pagesize) / 1024」の計算を行いキロバイト単位の結果を得ている。
pagesizeが 4096(4K) なので4倍なる。
そしてHomebrewでインストールするGNU timeは、全くパッチの当たっていないGNU time ver 1.7をFreeBSDのftpサーバーから取得しているために壮大なバグが残ったままです。
…してHomebrewのgnu-timeフォーミュラにパッチを追加してプルリクエストしちゃったのですが、upstreamにイシュってと…
- OS毎(getrusage)に単位が違う値を返してくるgetrusage
- 元のコードは作成時のru_maxrssがページ単位だったのでコードは正しい
- 現在、各配布先で独自のパッチがある
こんな感じでバグとは言えないけど、OS毎の対応を行うなら新旧含めて、どこまで対応するのか難しい。
んで、結論は各環境でパッチによる対応が良いのでは...Red Hatとか別のパッチもあたってるし...
そして、これらを英語で説明できるほど達者じゃ無い...ノω≦)これが一番高いハードル。
「PHPのforeach(range())は、forループの代用にはならないよ」
はじめに
添字などのループ処理に「for」ではなく「foreachとrange」を組み合わせたループで添字をカウントアップしているコードを見かけました。
見た目は、他の言語のイテレータのような雰囲気を出しているが、これはPHPでダメな書き方なのでメモ。
説明
何がダメかと言うと、range()はイテレータ(or ジェネレータ)を生成するのでなく、配列を生成する。
10回くらいのループならば気が付かないかもしれません。
<?php foreach(range(1, 10) as $i) { echo $i . PHP_EOL; }
でも、100万回のループならば・・・
<?php foreach(range(1, 1000000) as $i) { echo $i . PHP_EOL; }
メモリーを確保出来ずにエラーとなります。
php.iniのmemory_limitをデフォルト値の128Mから大きくしても、根本の問題は解決しません。
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in xxx.php
「Windows7でVagrantを更新インストールした環境で、"bsdtarが見つからない"となる件について」
問題
発生した問題
下記のエラーメッセージが表示されBoxファイルの追加に失敗する。
F:\vm\z001>type vagrantfile # -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu1404" config.vm.box_url = "f:\\boxs\\ubuntu-14-04-x64-virtualbox.box" end F:\vm\z001>vagrant box add ubuntu1404 "f:\\boxs\\ubuntu-14-04-x64-virtualbox.box" ==> box: Adding box 'ubuntu1404' (v0) for provider: box: Downloading: file://f:/boxs/ubuntu-14-04-x64-virtualbox.box box: Progress: 100% (Rate: 163M/s, Estimated time remaining: --:--:--) The executable 'bsdtar' Vagrant is trying to run was not found in the %PATH% variable. This is an error. Please verify this software is installed and on the path.
エラーメッセージは「実行ファイルの"bsdtar"がサーチパス上から見つからない。インストールしてパスを通してください」みたいな感じです。
対応
Vagrant 1.5.2 をアンインストールしてから、Vagrant 1.6.5 を新規インストールする。
ネット上を調べると、「bsdtar.exeを別途インストールする」や「PATH環境変数へ、別の場所にあるbsdtar.exeのパスを追加する」などが見つかりましたが、新規インストールが現状での最良だと思います。(理由は後ほど)
調査と原因
まず、vagrant 1.6.5を新規インストールした場合と、更新インストールした場合で何が異なるのか?
bsdtar.exeに注目して調べると「C:\HashiCorp\Vagrant\embedded\gnuwin32\bin」の内容が異なります。
更新インストールした場合
C:\HashiCorp\Vagrant\embedded\gnuwin32\bin>dir ドライブ C のボリューム ラベルは SYSTEM(SSD) です ボリューム シリアル番号は 8A9F-F559 です C:\HashiCorp\Vagrant\embedded\gnuwin32\bin のディレクトリ 2014/10/13 18:53 <DIR> . 2014/10/13 18:53 <DIR> .. 2014/04/29 22:48 1,209,161 libarchive.dll 1 個のファイル 1,209,161 バイト 2 個のディレクトリ 176,688,869,376 バイトの空き領域
新規インストールした場合
C:\HashiCorp\Vagrant\embedded\gnuwin32\bin>dir ドライブ C のボリューム ラベルは SYSTEM(SSD) です ボリューム シリアル番号は 8A9F-F559 です C:\HashiCorp\Vagrant\embedded\gnuwin32\bin のディレクトリ 2014/10/13 19:28 <DIR> . 2014/10/13 19:28 <DIR> .. 2014/04/29 22:50 1,252,396 bsdcpio.exe 2014/04/29 22:50 1,281,328 bsdtar.exe 2014/04/29 22:48 1,209,161 libarchive.dll 3 個のファイル 3,742,885 バイト 2 個のディレクトリ 176,117,678,080 バイトの空き領域
「bsdtar.exe」が無くなっています。
これはインストーラにより削除されたことになるのですが、更新インストール時のログに原因となりそうなメッセージが出力されています。
更新インストール時のログ(抜粋)
... MSI (c) (AC:30) [18:49:28:836]: Disallowing installation of component: {BCBBCB44-984B-4F12-9EAE-9F32C977168F} since the same component with higher versioned keyfile exists MSI (c) (AC:30) [18:49:28:836]: Disallowing installation of component: {46C1C17F-C76E-4445-ACC8-D4FEE653035F} since the same component with higher versioned keyfile exists ... MSI (s) (88:64) [18:50:35:698]: Executing op: ComponentRegister(ComponentId={BCBBCB44-984B-4F12-9EAE-9F32C977168F},KeyPath=C:\HashiCorp\Vagrant\embedded\gnuwin32\bin\bsdtar.exe,State=3,,Disk=1,SharedDllRefCount=2,BinaryType=0) 1: {3D24EE12-E0CF-41EC-8182-361ECF575656} 2: {BCBBCB44-984B-4F12-9EAE-9F32C977168F} 3: C:\HashiCorp\Vagrant\embedded\gnuwin32\bin\bsdtar.exe ...
「Disallowing installation of component: {GUID} since the same component with higher versioned keyfile exists」が、「既に更新が必要のないバージョンが存在しているのでインストールしません」な感じです。
長い英数字文字列{GUID}が対象ファイルを表しています。ログの後半で{GUID}に対応するファイルが「gunwin32\bin\bsdtar.exe」であることが確認できます。
Windows Installer の 更新時のルール(
File Versioning Rules (Windows))で判定した結果、インストール対象から外されているようです。(Vagrant 1.5.2 と 1.6.5 でインストールされる「bsdtar.exe」は同じなので更新する必要がないのですが)
その後、何故かインストール処理中に「gunwin32\bin」以下のファイルが削除されます。
「bsdtar.exe」も一緒に削除された後、インストール対象から外れていためインストールされず「bsdtar.exe」が消えてしまう結果となるようです。
まとめ
msi形式のインストーラの作成時の設定か、Windows Installer特有の問題なのかは別として、vagrant 1.6.5のインストーラ単体では内容物に不足はありません。
「bsdtar.exe」を別途ダウンロードしてきて「gunwin32\bin」以下へ配置しても、他のいくつかのファイルが消えているので不安定な環境が残るだけです。
また、更新インストールで問題が発生する状態でも「C:\HashiCorp\Vagrant\embedded\mingw\bin」に「bsdtar.exe」があります(ファイルサイズ異なり名前は同じだが別もの)。
今回のようにインストール方法を変えて差分を確認していない人が、残っている同名のファイルへパスを通す対応をしているようです。
Vagrant 1.6.5のインストーラに「bsdtar.exe」がないわけでもなく、1.6.5で新規にパスの設定が必要になったわけでもありません。
プロダクトとして想定されているインストール結果は、1.6.5のインストーラで新規インストールした状態であり、問題が発生する更新インストールの状態ではありません。
不安定な状態に場当たり的な対応はしないで、想定されている状態にした方が良いとの判断で、現状では新規インストールが最良であると考えます。
場当たり対応をした環境で「おれの環境では発生するんだが」な問題を報告されても対応できないからねっ≧ω≦)b!!
「Vagrantで、apt-get upgradeを含んだプロビジョニングで発生するエラーについて」
はじめに
VagrantでUbuntu14.04 Serverの環境構築を行っていたところ、今まで成功していたプロビジョニングのコードが失敗するようになりました。
調査の結果、原因と解決方法を以下にまとめます。
作業環境
ホストOS
Ubuntu14.04 Desktop 64bit
Vagrant 1.6.3
VirtualBox 4.3.12.r93733
ゲストOS
Ubuntu14.04 Server 64bit
概要
- プロビジョニングが失敗した時の状態
- 原因の調査
- 解決方法の調査
- 解決方法
- まとめ
1.プロビジョニングが失敗した時の状態
環境構築に使用したコード
Vagrantfile
# -*- mode: ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu1404" config.vm.provision :shell, inline:<<-EOS apt-get upgrade apt-get -y upgrade EOS end
失敗した時の出力(抜粋)
... ==> default: Package configuration┌──────────────────────────┤ Configuring grub-pc ├──────────────────────────┐│││ The GRUB boot loader was previously installed to a disk that is no││ longer present, or whose unique identifier has changed for some reason. ││ It is important to make sure that the installed GRUB core image stays in ││ sync with GRUB modules and grub.cfg. Please check again to make sure││ that GRUB is written to the appropriate boot devices.││││ If you're unsure which drive is designated as boot drive by your BIOS, ││ it is often a good idea to install GRUB to all of them.││││ Note: it is possible to install GRUB to partition boot records as well, ││ and some appropriate partitions are offered here. However, this forces ││ GRUB to use the blocklist mechanism, which makes it less reliable, and ││ therefore is not recommended.││││<Ok>│││└───────────────────────────────────────────────────────────────────────────┘ ==> default: Failed to open terminal.64 (1:5.14-2ubuntu3.1) ... ==> default: debconf: whiptail output the above errors, giving up! ==> default: dpkg: error processing package grub-pc (--configure): ==> default: subprocess installed post-installation script returned error exit status 255 ...
2.原因の調査
失敗時の出力からプロビジョニング中にgrub-pcの設定画面を開こうとして失敗していることが分かります。
プロビジョニング中に入力を求める設定画面は使用できません。
この設定画面を回避する必要があります。
何故、grub-pcパッケージの設定画面が開くようになったか?
apt-get upgradeで更新対象になっているので、BOXファイル作成時よりgrub-pcのバージョンが上がった事が推測できます。
プロビジョニングをせずに、環境を構築しSSHで接続後、grub-pcパッケージのバージョンを確認します。
vagrant@ubuntu-1404:~$ sudo dpkg --list | grep grub ii grub-common 2.02~beta2-9 amd64 GRand Unified Bootloader (common files) ii grub-gfxpayload-lists 0.6 amd64 GRUB gfxpayload blacklist ii grub-pc 2.02~beta2-9 amd64 GRand Unified Bootloader, version 2 (PC/BIOS version) ii grub-pc-bin 2.02~beta2-9 amd64 GRand Unified Bootloader, version 2 (PC/BIOS binaries) ii grub2-common 2.02~beta2-9 amd64 GRand Unified Bootloader (common files for version 2)
「2.02-beta2-9」である事が分かります。
次に手入力で、apt-get upgradeを行います。
設定画面が表示されるのですが、何故かGRUBのインストール先デバイスの問い合せです(原因は後ほど)。
構築している仮想環境のHDDは1つなので、/dev/sda (42949 MB: VBOX_HARDDISK)にチェックを入れてOKとします。
ちょっと小さいですが whiptail を使用した画面が表示されることの確認です。
apt-get upgrade後の、grub-pcパッケージのバージョンを確認します。
vagrant@ubuntu-1404:~$ sudo dpkg --list | grep grub sudo dpkg --list | greo grub ii grub-common 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader (common files) ii grub-gfxpayload-lists 0.6 amd64 GRUB gfxpayload blacklist ii grub-pc 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader, version 2 (PC/BIOS version) ii grub-pc-bin 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader, version 2 (PC/BIOS binaries) ii grub2-common 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader (common files for version 2)
「2.02-beta2-9ubuntu1」にバージョンが変わっています。
「UbuntuUpdates.org」で確認すると「2.02-beta2-9」をベースにしてパッチが当たってるようです。
http://www.ubuntuupdates.org/package/core/trusty/universe/updates/grub2
grub-pcのバージョンが上がったことは確認できました。
3.解決方法の調査
この設定画面を非表示で/dev/sdaが選択される方法を考えます。
環境変数 DEBIAN_FRONTEND に noninteractive を設定後、デフォルト値を指定してupgradeする方法を考えましが、今回の問題を解決することはできませんでした。
別の方法を調べていたところ、debianには自動化のための設定値をテキストファイルではなくデータベースで与える仕組みがあることが分かりました。
その仕組みに対応しているパッケージでは、データベースから設定値を取得するそうです。
データベースを操作するコマンドとして、debconf系のコマンドが用意されています。
設定と参照に使用するコマンドの例
設定(パッケージ/項目単位)
$ echo "set grub-pc/install_devices /dev/sda" | debconf-communicate
参照(パッケージ/項目単位)
$ echo "get grub-pc/install_devices /dev/sda" | debconf-communicate
参照(パッケージ単位)
$ debconf-show grub-pc
grub-pcパッケージは、この仕組みに対応しているようです。
検証のために、環境を再構築して upgrade 実行前に戻します。
upgrade 前にgrub-pcの設定値を確認します。
vagrant@ubuntu-1404:~$ sudo debconf-show grub-pc grub2/linux_cmdline_default: quiet splash grub-pc/kopt_extracted: false grub-pc/mixed_legacy_and_grub2: true grub-pc/postrm_purge_boot_grub: false grub-pc/install_devices_empty: false grub-pc/install_devices_disks_changed: grub2/linux_cmdline: grub-pc/hidden_timeout: true grub2/kfreebsd_cmdline: grub-pc/disk_description: grub2/kfreebsd_cmdline_default: quiet splash * grub-pc/install_devices: /dev/disk/by-id/ata-VBOX_HARDDISK_VB36ceb79a-609a9c78 grub-pc/timeout: 10 grub-pc/chainload_from_menu.lst: true grub-pc/install_devices_failed_upgrade: true grub-pc/partition_description: grub2/device_map_regenerated: grub-pc/install_devices_failed: false
これから設定する予定の install_devices に値が設定されていますが、/dev/sda ではなく/dev/disk/by-id 以下のパスになってます。
ちょっと、/dev/disk/by-id 以下を覗いてみます。
vagrant@ubuntu-1404:~$ ll /dev/disk/by-id total 0 drwxr-xr-x 2 root root 200 Aug 8 13:58 ./ drwxr-xr-x 4 root root 80 Aug 8 13:58 ../ lrwxrwxrwx 1 root root 9 Aug 8 13:58 ata-VBOX_HARDDISK_VBe49e1f29-745fffe8 -> ../../sda lrwxrwxrwx 1 root root 10 Aug 8 13:58 ata-VBOX_HARDDISK_VBe49e1f29-745fffe8-part1 -> ../../sda1 lrwxrwxrwx 1 root root 10 Aug 8 13:58 ata-VBOX_HARDDISK_VBe49e1f29-745fffe8-part2 -> ../../sda2 lrwxrwxrwx 1 root root 10 Aug 8 13:58 ata-VBOX_HARDDISK_VBe49e1f29-745fffe8-part5 -> ../../sda5 lrwxrwxrwx 1 root root 10 Aug 8 13:59 dm-name-ubuntu--1404--vg-root -> ../../dm-0 lrwxrwxrwx 1 root root 10 Aug 8 13:59 dm-name-ubuntu--1404--vg-swap_1 -> ../../dm-1 lrwxrwxrwx 1 root root 10 Aug 8 13:59 dm-uuid-LVM-RCIg1EIc6CV1RnqFdUzmRFCB3TyX01FBj9TLfcBDKgLxCDXaac9gZ9FnuetB2xmM -> ../../dm-0 lrwxrwxrwx 1 root root 10 Aug 8 13:59 dm-uuid-LVM-RCIg1EIc6CV1RnqFdUzmRFCB3TyX01FBnmTl3brIQysPjdZwUTwfqdwChucxk6jW -> ../../dm-1 vagrant@ubuntu-1404:~$
現在の設定値に相当するパスが存在していません。
結論から言うと、BOXファイルから環境を構築する度に VBOX_HARDDISK_VB~のid部分が変わります。
データベース上の設定値は更新されません。
よって、実在しないパスとなり、grub-pcパッケージはインストール先を問い合せる画面を表示することになります。
環境変数 DEBIAN_FRONTEND でも表示を抑えられなかった理由はこれです。
では、手入力により解決できるか検証します。
設定値の登録と確認
debconf-コマンドの実行には root権限が必要となります。
プロビジョニング中はコマンドが root権限で実行されますが手入力なので sudo が必要です。
vagrant@ubuntu-1404:~$ sudo sh -c 'echo "set grub-pc/install_devices /dev/sda" | debconf-communicate' 0 value set vagrant@ubuntu-1404:~$ sudo sh -c 'echo "get grub-pc/install_devices" | debconf-communicate' 0 /dev/sda vagrant@ubuntu-1404:~$
upgradeの実行
vagrant@ubuntu-1404:~$ sudo apt-get -y upgrade ... Setting up grub-common (2.02~beta2-9ubuntu1) ... Setting up grub2-common (2.02~beta2-9ubuntu1) ... Setting up grub-pc-bin (2.02~beta2-9ubuntu1) ... Setting up grub-pc (2.02~beta2-9ubuntu1) ... Installing for i386-pc platform. Installation finished. No error reported. Generating grub configuration file ... Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported. Found linux image: /boot/vmlinuz-3.13.0-24-generic Found initrd image: /boot/initrd.img-3.13.0-24-generic done Setting up linux-firmware (1.127.5) ... Setting up language-pack-en (1:14.04+20140707) ... Setting up language-pack-en-base (1:14.04+20140707) ... Generating locales... en_AG.UTF-8... up-to-date en_AU.UTF-8... up-to-date en_BW.UTF-8... up-to-date en_CA.UTF-8... up-to-date en_DK.UTF-8... up-to-date en_GB.UTF-8... up-to-date en_HK.UTF-8... up-to-date en_IE.UTF-8... up-to-date en_IN.UTF-8... up-to-date en_NG.UTF-8... up-to-date en_NZ.UTF-8... up-to-date en_PH.UTF-8... up-to-date en_SG.UTF-8... up-to-date en_US.UTF-8... up-to-date en_ZA.UTF-8... up-to-date en_ZM.UTF-8... up-to-date en_ZW.UTF-8... up-to-date Generation complete. Setting up language-pack-gnome-en (1:14.04+20140707) ... Setting up language-pack-gnome-en-base (1:14.04+20140707) ... Processing triggers for libc-bin (2.19-0ubuntu6.1) ... Processing triggers for ureadahead (0.100.0-16) ... Processing triggers for initramfs-tools (0.103ubuntu4.2) ... update-initramfs: Generating /boot/initrd.img-3.13.0-24-generic vagrant@ubuntu-1404:~$ sudo dpkg --list | grep grub ii grub-common 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader (common files) ii grub-gfxpayload-lists 0.6 amd64 GRUB gfxpayload blacklist ii grub-pc 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader, version 2 (PC/BIOS version) ii grub-pc-bin 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader, version 2 (PC/BIOS binaries) ii grub2-common 2.02~beta2-9ubuntu1 amd64 GRand Unified Bootloader (common files for version 2) vagrant@ubuntu-1404:~$
4.解決方法
今回の問題に対応したプロビジョニングのコードを含んだ Vagrantfile の内容が以下になります。
debconf-communicate の一行を追加しただけですが・・・
# -*- mode: ruby -*- # vi: set ft=ruby : VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "ubuntu1404" config.vm.provision :shell, inline:<<-EOS echo "set grub-pc/install_devices /dev/sda" | debconf-communicate apt-get update apt-get -y upgrade EOS end
5.まとめ
実際に問題が発生した Vagrantfile は、もっと複雑な処理を行っていたのですが、変更していない箇所でエラーが発生していたので原因の特定に回り道をしてしまいました。
今回初めて debconf関連の情報を知ることができて良かった。
これで、この仕組みに対応している他のパッケージで同じ問題が発生しても悩む事はなさそうです♪
「Ubuntu14.04 Serverのインフラのテスト自動化(vagrant、serverspec、puppet)」|WEB+DB Press vol.80の特集記事から
はじめに
Rubyのための環境構築を行っているうちにInfrastructure as Codeへ軸が移ってきました。
構築した結果の確認をそろそろ自動化したいと考えているところで、WEB+DB Press vol.80で丁度良く特集が組まれたので、これを参考にしてserverspecの習得も始めました。
ただし、作業環境と対象環境は普段使用している環境で行いました。その結果、いくつかの違いが出たので、それをまとめました。
参考書籍
- 作者: 鶴長鎮一,宮下剛輔,縣俊貴,中村知成,西尾泰和,新井俊一,南川毅文,伊藤直也,石垣憲一,浅木朗,渡邊恵太,中島聡,はまちや2,竹原,川添貴生,河合宜文,WEB+DB PRESS編集部
- 出版社/メーカー: 技術評論社
- 発売日: 2014/04/24
- メディア: 大型本
- この商品を含むブログ (5件) を見る
概要
作業環境
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
手順
- serverspecのインストール
- 必要なディレクトリとファイルの作成
- テスト駆動インフラの実践(テスト失敗)
- プロビジョニング後、再テストの実施(テスト成功)
- テスト駆動インフラの繰り返し(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.テスト駆動インフラの実践(テスト失敗)
テスト結果を見やすくするための設定ファイルも作成します。
テストコードの作成
- 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)>'
二種類のコマンドのどちらかが成功した場合にテスト成功となるようです。
まず、コマンドを手入力してみます。
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での記述方法だけでなく、どうやってチェックしているかを知らないと新しい要素のテストコードを記述できないことが分かりました。
実施してみて注意することが分かったので、今後は他の条件のテストも行って習得度を上げていきます。
「Vagrant initで最小限のコメントだけが含まれたVagrantfileを作成する」|ただいまRubyの修行中
はじめに
vagrant intiで作成されるVagrantfileのコード部分は小さいのでゼロから入力してもいいのですが、少しでも効率を上げるなら利用したいところです。しかし、作成されたVagrantfileはコメントが多すぎてとてもベースとして利用できません。
そこで、最小限のコメントのVagrantfileを作成するオプションを指定します。
方法
公式サイトのドキュメントにある--minimalを指定します。
vagrant init - Command-Line Interface - Vagrant Documentation
※ ソースコードを確認すると-mとする短縮があるので、実際は、こちらを指定します。
コマンド
stupiddog@pc001:~/vm/a003$ vagrant init ubuntu1404 ~/boxs/ubuntu-14-04-x64-virtualbox.box -m A `Vagrantfile` has been placed in this directory. You are now ready to `vagrant up` your first virtual environment! Please read the comments in the Vagrantfile as well as documentation on `vagrantup.com` for more information on using Vagrant.
作成されたVagrantfileの内容
# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 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" end
まとめ
これで少し効率アップです。
「Packerを利用したUbuntu14.04 ServerのVagrant用Boxファイルの作成」|ただいまRubyの修行中
はじめに
Ubuntu 14.04 Serverが公開されたので新しい環境を作成することにしました。
まだ、適当なUbuntu 14.04 ServerのBoxファイルが無いので今後のために自作する方法を習得しておきます。
Packerを利用する方法を探していたら必要な設定ファイル一式を公開しているサイトを見つけたので、有難く利用させて頂きます。
参照サイト
packer - Ubuntu 14.04 を Vagrant に準備する - Qiita
時雨堂さんのPackerテンプレート
shiguredo/packer-templates · GitHub
概要
作業環境
Ubuntu 14.04 Desktop 64bit |
VirtualBox 4.3.12r93733 |
Vagrant 1.6.2 |
Packer v0.6.0 |
手順概要
- VirtualBoxのインストール
- Vagrantのインストール
- Packerのインストール
- Packerテンプレートの取得
- Boxファイルの生成
- 生成したBoxファイルで仮想環境の構築とssh接続テスト
1.VirtualBoxのインストール
公式サイトからVirtualBoxのインストーラーをダウンロードする。
Downloads – Oracle VM VirtualBox
(ファイル「virtualbox-4.3_4.3.10-93012~Ubuntu~raring_amd64.deb」)
stupiddog@pc001:~$ dpkg -i ~/Downloads/virtualbox-4.3_4.3.12-93733~Ubuntu~raring_amd64.deb ... stupiddog@pc001:~$ vboxmanage -v 4.3.12r93733
2.Vagrantのインストール
公式サイトからVagrantのインストーラーをダウンロードする。
Download Vagrant - Vagrant
(ファイル「vagrant_1.6.2_x86_64.deb」)
stupiddog@pc001:~$ sudo dpkg -i ~/Downloads/vagrant_1.6.2_x86_64.deb ... stupiddog@pc001:~$ vagrant -v Vagrant 1.6.2
3.Packerのインストール
公式サイトからPackerのパッケージをダウンロードする。
Downloads - Packer
(ファイル「0.6.0_linux_amd64.zip」)
公式サイトのドキュメントに従ってファイルを展開しパスを通します。
Install Packer - Packer
今回はユーザーのホームディレクトリへ配置しました。
stupiddog@pc001:~$ unzip ~/Downloads/0.6.0_linux_amd64.zip -d ~/packer ... stupiddog@pc001:~$ echo 'export "$HOME/packer:$PATH"' >> ~/.bashrc stupiddog@pc001:~$ source ~/.bashrc stupiddog@pc001:~$ packer -v Packer v0.6.0
4.Packerテンプレートの取得
Githubからファイルを取得(clone)する
stupiddog@pc001:~$ git clone https://github.com/shiguredo/packer-templates.git ~/packer-templates Cloning into '/home/stupiddog/packer-templates'... remote: Reusing existing pack: 133, done. remote: Total 133 (delta 0), reused 0 (delta 0) Receiving objects: 100% (133/133), 21.33 KiB | 0 bytes/s, done. Resolving deltas: 100% (55/55), done. Checking connectivity... done.
5.Boxファイルの生成
取得したPackerテンプレートの中にはバージョン毎にファイルが分けられています。
テンプレートは、VirtualBox以外に VMWareにも対応していますが今回は、VirtualBoxのBoxイメージのみを生成します。
Packerコマンドのオプションとして、-only=virtualbox-isoを指定して実行します。
stupiddog@pc001:~$ cd ~/packer-templates/ubuntu-14.04 stupiddog@pc001:~$ packer build -only=virtualbox-iso template.json stupiddog@pc001:~/packer-templates/ubuntu-14.04$ packer build -only=virtualbox-iso template.json virtualbox-iso output will be in this color. ==> virtualbox-iso: Downloading or copying Guest additions checksums virtualbox-iso: Downloading or copying: http://download.virtualbox.org/virtualbox/4.3.12/SHA256SUMS ==> virtualbox-iso: Downloading or copying Guest additions virtualbox-iso: Downloading or copying: http://download.virtualbox.org/virtualbox/4.3.12/VBoxGuestAdditions_4.3.12.iso ... virtualbox-iso (vagrant): Compressing: metadata.json virtualbox-iso (vagrant): Compressing: packer-virtualbox-iso-disk1.vmdk Build 'virtualbox-iso' finished. ==> Builds finished. The artifacts of successful builds are: --> virtualbox-iso: 'virtualbox' provider box: ubuntu-14-04-x64-virtualbox.box drwxrwxr-x 5 stupiddog stupiddog 4096 5月 21 22:28 ./ drwxrwxr-x 9 stupiddog stupiddog 4096 5月 21 20:46 ../ drwxrwxr-x 2 stupiddog stupiddog 4096 5月 21 20:46 http/ drwxr-xr-x 2 stupiddog stupiddog 4096 5月 21 21:07 packer_cache/ drwxrwxr-x 2 stupiddog stupiddog 4096 5月 21 20:46 scripts/ -rw-rw-r-- 1 stupiddog stupiddog 4108 5月 21 20:46 template.json -rw-rw-r-- 1 stupiddog stupiddog 511869354 5月 21 22:28 ubuntu-14-04-x64-virtualbox.box
Ubuntu14.04 ServerのISOイメージを公式サイトからダウンロードし、エラーが無ければ生成されたBoxファイルがカレントディレクトリに作成されます。
(ファイル「ubuntu-14-04-x64-virtualbox.box」)
6.生成したBoxファイルで仮想環境の構築とssh接続テスト
作業ディレクトリ「~/vm/a001」を作成し、Vagrantfileを下記の内容で配置してvagrant upコマンドを実行します。
仮想環境用のディレクトリを作成する
管理用ディレクトリを作成して、そこをカレントディレクトリとします。
stupiddog@pc001:~$ mkdir -p ~/vm/a001 stupiddog@pc001:~$ cd ~/vm/a001 stupiddog@pc001:~/vm/a001$ tree ~/vm/a001 /home/stupiddog/vm/a001 └── vagrantfile 0 directories, 1 file
Vagrantfileを作成する
管理用ディレクトリに以下の内容で「vagrantfile」ファイルを作成します。
VAGRANT_API_VERSION = "2" Vagrant.configure(VAGRANT_API_VERSION) do |config| config.vm.box = "ubuntu1404" config.vm.box_url = "~/packer-tamplates/ubuntu-14-04-x64-virtualbox.box" config.vm.hostname = "a001.local" config.vm.network "private_natwork", ip:"192.168.100.100" end
仮想環境を構築する
stupiddog@pc001:~/vm/a001$ cat vagrantfile VAGRANT_API_VERSION = "2" Vagrant.configure(VAGRANT_API_VERSION) do |config| config.vm.box = "ubuntu1404" config.vm.box_url = "~/packer-tamplates/ubuntu-14-04-x64-virtualbox.box" config.vm.hostname = "a001.local" config.vm.network "private_network", ip:"192.168.100.100" end stupiddog@pc001:~/vm/a001$ vagrant up Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'ubuntu1404'... ==> default: Matching MAC address for NAT networking... ==> default: Setting the name of the VM: a001_default_1400689238903_18288 ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat default: Adapter 2: hostonly ==> default: Forwarding ports... default: 22 => 2222 (adapter 1) ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2222 default: SSH username: vagrant default: SSH auth method: private key default: Warning: Connection timeout. Retrying... ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... ==> default: Setting hostname... ==> default: Configuring and enabling network interfaces... ==> default: Mounting shared folders... default: /vagrant => /home/stupiddog/vm/a001 stupiddog@pc001:~/vm/a001$ 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@a001:~$