#contents ** Serverspecとは何か? [#yf8d7104] - 概要 -- サーバー構成のテスト -- 特定のツールに依存しない - 公式サイト: serverspec.org - 知識 -- Vagrant -- Ruby -- RSpec -- Itamae - 全体像 -- host: Ruby, Itamae, Serverspec -- web: Apache, PHP ** サーバーの設定をしていこう [#o455a9fd] - 利用可能なBoxファイルを検索 -- Atlas >> Discover Vagrant Boxes - 'bento/centos-6.7'のVagrant boxを利用 - Vagrantfileを生成 $ cd ~/Documents/MyVagrant $ mkdir serverspec_lessons $ cd serverspec_lessons $ vagrant init bento/centos-6.7 - Vagrantfileを開き下記をコメントアウト $ vi Vagrantfile config.vm.box = "bento/centos-6.7" - 下記を貼り付け config.vm.define "host" do |node| node.vm.box = "bento/centos-6.7" node.vm.hostname = "host" node.vm.network :private_network, ip: "192.168.33.10" end config.vm.define "web" do |node| node.vm.box = "bento/centos-6.7" node.vm.hostname = "web" node.vm.network :private_network, ip: "192.168.33.11" end $ vagrant up - Vagrant確認 $ vagrant status Current machine states: host running (virtualbox) web running (virtualbox) This environment represents multiple VMs. The VMs are all listed above with their current state. For more information about a specific VM, run `vagrant status NAME`. - webに対してssh configを設定 $ vagrant ssh host $ vi .ssh/config Host web HostName 192.168.33.11 $ chmod 600 .ssh/config - 秘密鍵/公開鍵作成 $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/home/vagrant/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: - webに公開鍵を転送 &color(red){*};Vagrantユーザーのデフォルトパスワードは 'vagrant' [vagrant@host ~]$ ssh-copy-id web The authenticity of host '192.168.33.11 (192.168.33.11)' can't be established. RSA key fingerprint is 90:d8:41:6f:c5:39:1d:54:0d:43:4e:34:dc:f1:d2:6b. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '192.168.33.11' (RSA) to the list of known hosts. vagrant@192.168.33.11's password: - SSH接続確認 $ ssh web $ exit ** Serverspecをインストールしよう [#acee2252] - hostにgitをインストール $ sudo yum -y install git - 環境初期構築用のスクリプト&color(red){*};を dotinstallres/centos65 リポジトリからダウンロード&hostに対して実行 -- &color(red){*}; run.sh: Ansibleインストール, main.yml実行 -- main.yml: CentOS初期設定, Apache, PHP 5.6, MySQL, Ruby 2.2.2 (rbenv/ruby-build), Node.jsインストール -- php.ini.custom: main.ymlより参照。php.iniの設定内容を記述 -- my.cnf.custom: main.ymlより参照。my.cnfの設定内容を記述 -- bash_profile.custom: main.ymlより参照。bash_profileの設定内容を記述 $ git clone https://github.com/dotinstallres/centos65.git $ cd centos65 $ ./run.sh .... .... PLAY RECAP ********************************************************************* localhost : ok=32 changed=31 unreachable=0 failed=0 - シェルの再起動 $ exec $SHELL -l - ruby確認 $ ruby -v ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-linux] - インストール済みGem一覧の表示(rakeがインストールされていることを確認) $ gem list *** LOCAL GEMS *** bigdecimal (1.2.6) io-console (0.4.3) json (1.8.1) minitest (5.4.3) power_assert (0.2.2) psych (2.0.8) rake (10.4.2) rdoc (4.2.0) test-unit (3.0.8) - itamaeとserverspecをインストール $ gem install itamae serverspec - gem list確認 $ gem list *** LOCAL GEMS *** ansi (1.5.0) .... diff-lcs (1.3) hashie (3.5.5) .... itamae (1.9.11) .... multi_json (1.12.1) net-scp (1.2.1) net-ssh (4.1.0) net-telnet (0.1.1) .... rspec (3.5.0) rspec-core (3.5.4) rspec-expectations (3.5.0) rspec-its (1.2.0) rspec-mocks (3.5.0) rspec-support (3.5.0) schash (0.1.2) serverspec (2.38.0) sfl (2.3) specinfra (2.67.2) .... thor (0.19.4) $ cd ** serverspec-initを使ってみよう [#fdc2e94f] - Itamaeの設定ファイル(recipe.rb)作成 $ mkdir myproject $ cd myproject/ $ mkdir cookbooks $ cd cookbooks/ $ vi recipe.rb $ cd .. - serverspec-initコマンドを使ってserverspecの設定ファイルを自動作成 $ pwd /home/vagrant/myproject $ 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: n Input target host name: web + spec/ + spec/web/ + spec/web/sample_spec.rb + spec/spec_helper.rb + Rakefile + .rspec - /home/vagrant/myproject配下のファイル構造 /home/vagrant/myproject |--.rspec |--Rakefile |--cookbooks | |--recipe.rb |--spec | |--spec_helper.rb | |--web | | |--sample_spec.rb - Apacheに関するspecファイルを作成(デフォルトのsample_spec.rbは削除) $ rm spec/web/sample_spec.rb $ vi spec/web/httpd_spec.rb ** はじめてのテストをしてみよう [#v932faab] - テスト駆動開発の手順に沿ってテストを記述 + fail: 失敗するテストを書く + pass: テストを通るようにする + refactor: リファクタリングをする - httpdのテストコード(myproject/spec/web/httpd_spec.rb) # 1. fail # 2. pass # 3. refactor require 'spec_helper' describe package('httpd') do it { should be_installed } end - テスト実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed (FAILED - 1) Failures: 1) Package "httpd" should be installed On host `web' Failure/Error: it { should be_installed } expected Package "httpd" to be installed sudo -p 'Password: ' /bin/sh -c rpm\ -q\ httpd package httpd is not installed # ./spec/web/httpd_spec.rb:8:in `block (2 levels) in <top (required)>' Finished in 1.08 seconds (files took 0.5465 seconds to load) 1 example, 1 failure Failed examples: rspec ./spec/web/httpd_spec.rb:8 # Package "httpd" should be installed /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb failed - Itamaeの設定ファイル編集(myproject/cookbooks/recipe.rb) package 'httpd' - Itamae実行(dry run) $ itamae ssh -h web cookbooks/recipe.rb -n - Itamae実行 $ itamae ssh -h web cookbooks/recipe.rb INFO : Starting Itamae... INFO : Recipe: /home/vagrant/myproject/cookbooks/recipe.rb INFO : package[httpd] installed will change from 'false' to 'true' - テスト再実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed Finished in 0.64223 seconds (files took 0.43663 seconds to load) 1 example, 0 failures ** ResourceとMatcherを調べてみよう [#u8cd6585] - 上記テストの例では Resourceは package('httpd') で Matcherは should be_installed - ResourceとMatcherの一覧は公式サイト >> Resource Types で確認可能 ** httpdのテストをしてみよう [#o39b3d36] - httpdが起動しているか/80番ポートでListenしているかのテスト(httpd_spec.rb) # 1. fail # 2. pass # 3. refactor require 'spec_helper' describe package('httpd') do it { should be_installed } end describe service('httpd') do it { should be_enabled } it { should be_running } end describe port(80) do it { should be_listening } end - テスト実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed Service "httpd" should be enabled (FAILED - 1) should be running (FAILED - 2) Port "80" should be listening (FAILED - 3) Failures: 1) Service "httpd" should be enabled On host `web' Failure/Error: it { should be_enabled } expected Service "httpd" to be enabled sudo -p 'Password: ' /bin/sh -c chkconfig\ --list\ httpd\ \|\ grep\ 3:on # ./spec/web/httpd_spec.rb:12:in `block (2 levels) in <top (required)>' 2) Service "httpd" should be running On host `web' Failure/Error: it { should be_running } expected Service "httpd" to be running sudo -p 'Password: ' /bin/sh -c service\ httpd\ status httpd is stopped # ./spec/web/httpd_spec.rb:13:in `block (2 levels) in <top (required)>' 3) Port "80" should be listening On host `web' Failure/Error: it { should be_listening } expected Port "80" to be listening sudo -p 'Password: ' /bin/sh -c netstat\ -tunl\ \|\ grep\ --\ :80\\\ # ./spec/web/httpd_spec.rb:17:in `block (2 levels) in <top (required)>' Finished in 0.86085 seconds (files took 0.43814 seconds to load) 4 examples, 3 failures Failed examples: rspec ./spec/web/httpd_spec.rb:12 # Service "httpd" should be enabled rspec ./spec/web/httpd_spec.rb:13 # Service "httpd" should be running rspec ./spec/web/httpd_spec.rb:17 # Port "80" should be listening /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb failed - Itamaeの設定ファイル修正(recipe.rb) package 'httpd' service 'httpd' do action [:enable, :start] end - Itamae実行 $ itamae ssh -h web cookbooks/recipe.rb INFO : Starting Itamae... INFO : Recipe: /home/vagrant/myproject/cookbooks/recipe.rb INFO : service[httpd] enabled will change from 'false' to 'true' INFO : service[httpd] running will change from 'false' to 'true' - テスト再実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed Service "httpd" should be enabled should be running Port "80" should be listening Finished in 0.8126 seconds (files took 0.4321 seconds to load) 4 examples, 0 failures ** fileリソースを使ってみよう [#s04cf7bd] - index.htmlが存在しHello Worldという文字列が記述されているかのテスト(httpd_spec.rb) # 1. fail # 2. pass # 3. refactor require 'spec_helper' describe package('httpd') do it { should be_installed } end describe service('httpd') do it { should be_enabled } it { should be_running } end describe port(80) do it { should be_listening } end describe file('/var/www/html/index.html') do it { should be_file } it { should be_owned_by 'apache' } it { should be_grouped_into 'apache' } its(:content) { should match /Hello World/ } end - テスト実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed Service "httpd" should be enabled should be running Port "80" should be listening File "/var/www/html/index.html" should be file (FAILED - 1) should be owned by "apache" (FAILED - 2) should be grouped into "apache" (FAILED - 3) content should match /Hello World/ (FAILED - 4) Failures: 1) File "/var/www/html/index.html" should be file On host `web' Failure/Error: it { should be_file } expected `File "/var/www/html/index.html".file?` to return true, got false sudo -p 'Password: ' /bin/sh -c test\ -f\ /var/www/html/index.html # ./spec/web/httpd_spec.rb:21:in `block (2 levels) in <top (required)>' 2) File "/var/www/html/index.html" should be owned by "apache" On host `web' Failure/Error: it { should be_owned_by 'apache' } expected `File "/var/www/html/index.html".owned_by?("apache")` to return true, got false sudo -p 'Password: ' /bin/sh -c stat\ -c\ \%U\ /var/www/html/index.html\ \|\ grep\ --\ \\\^apache\\\$ # ./spec/web/httpd_spec.rb:22:in `block (2 levels) in <top (required)>' 3) File "/var/www/html/index.html" should be grouped into "apache" On host `web' Failure/Error: it { should be_grouped_into 'apache' } expected `File "/var/www/html/index.html".grouped_into?("apache")` to return true, got false sudo -p 'Password: ' /bin/sh -c stat\ -c\ \%G\ /var/www/html/index.html\ \|\ grep\ --\ \\\^apache\\\$ # ./spec/web/httpd_spec.rb:23:in `block (2 levels) in <top (required)>' 4) File "/var/www/html/index.html" content should match /Hello World/ On host `web' Failure/Error: its(:content) { should match /Hello World/ } expected "" to match /Hello World/ Diff: @@ -1,2 +1,2 @@ -/Hello World/ +"" sudo -p 'Password: ' /bin/sh -c cat\ /var/www/html/index.html\ 2\>\ /dev/null\ \|\|\ echo\ -n # ./spec/web/httpd_spec.rb:24:in `block (2 levels) in <top (required)>' Finished in 0.90728 seconds (files took 0.4069 seconds to load) 8 examples, 4 failures Failed examples: rspec ./spec/web/httpd_spec.rb:21 # File "/var/www/html/index.html" should be file rspec ./spec/web/httpd_spec.rb:22 # File "/var/www/html/index.html" should be owned by "apache" rspec ./spec/web/httpd_spec.rb:23 # File "/var/www/html/index.html" should be grouped into "apache" rspec ./spec/web/httpd_spec.rb:24 # File "/var/www/html/index.html" content should match /Hello World/ /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb failed - index.html作成 $ cd cookbooks/ $ mkdir files $ cd files/ $ vi index.html <html> Hello World </html> $ cd ../.. - Itamae設定ファイル修正(recipe.rb) package 'httpd' service 'httpd' do action [:enable, :start] end remote_file '/var/www/html/index.html' do owner 'apache' group 'apache' end - Itamae実行 $ itamae ssh -h web cookbooks/recipe.rb INFO : Starting Itamae... INFO : Recipe: /home/vagrant/myproject/cookbooks/recipe.rb INFO : remote_file[/var/www/html/index.html] exist will change from 'false' to 'true' INFO : remote_file[/var/www/html/index.html] modified will change from 'false' to 'true' INFO : remote_file[/var/www/html/index.html] owner will be 'apache' INFO : remote_file[/var/www/html/index.html] group will be 'apache' INFO : diff: INFO : --- /dev/null 2017-03-12 12:01:09.240000001 +0000 INFO : +++ /tmp/itamae_tmp/1489326611.9137843 2017-03-12 13:50:11.959835316 +0000 INFO : @@ -0,0 +1,3 @@ INFO : +<html> INFO : +Hello World INFO : +</html> - テスト再実行 $ rake spec /home/vagrant/.rbenv/versions/2.2.2/bin/ruby -I/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-support-3.5.0/lib:/home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/lib /home/vagrant/.rbenv/versions/2.2.2/lib/ruby/gems/2.2.0/gems/rspec-core-3.5.4/exe/rspec --pattern spec/web/\*_spec.rb Package "httpd" should be installed Service "httpd" should be enabled should be running Port "80" should be listening File "/var/www/html/index.html" should be file should be owned by "apache" should be grouped into "apache" content should match /Hello World/ Finished in 0.8986 seconds (files took 0.43226 seconds to load) 8 examples, 0 failures