serverspecでWindowsのテストをお試しする

お仕事でWindowsサーバをserverspecでテストしたい！という要件があり、ご自宅のWindows PCで色々と実験するための環境を作ってみた。

# 動作環境
ご自宅にはマトモな環境が無いので、WindowsマシンをホストOSにして、VirtualBoxでLinuxのゲストOSを作った。ゲストOSでserverspecを実行し、リモートでホストOSをテストできるようにする。

* ホストOS(テスト対象ホスト)
    * OSはWindows7 Home Premium
    * ゲストOS用にVirtualBox 4.3.2をインストール
* ゲストOS(serverspec実行環境)
    * テスト対象ホストのVirtualBoxで動作。ネットワーク設定は以下の通り。
        * アダプター1はNAT
        * アダプター2はホストオンリーアダプター
    * OSはCentOSで、事前にRubyがインストールされている。バージョンは以下の通り。
        * CentOS 6.3
        * Ruby 2.0.0p481

# serverspecの設定を行う
serverspec実行環境にserverspecをインストールする。

まずはserverspec用のディレクトリを作る。

````
$ mkdir serverspec
$ cd serverspec
````

Gemfileにserverspec等、必要なgemを書いてインストールする。
Windowsホストをリモートでテストする為に、winrmもインストールする。

````
$ vi Gemfile
$ cat Gemfile
source 'https://rubygems.org'

gem 'serverspec'
gem 'rake'
gem 'winrm'
$ bundle install --path=vendor/bundle
````

serverspec-initコマンドを実行し、設定のひな型を作成する。
OS typeに「Windows」、backend typeに「WinRM」を選択する。

````
bundle exec serverspec-init
Select OS type:

  1) UN*X
  2) Windows

Select number: 2

Select a backend type:

  1) WinRM
  2) Cmd (local)

Select number: 1

 + spec/
 + spec/localhost/
 + spec/localhost/httpd_spec.rb
 + spec/spec_helper.rb
 + Rakefile
````

動く事が確認出来れば良いので、とりあえずホスト名をテストするシナリオを作成する。
※デフォで作成されるhttpd_specは、邪魔だったので一旦削除した。

````
$ vi spec/localhost/host_spec.rb
$ cat spec/localhost/host_spec.rb
require 'spec_helper'

describe command('hostname') do
  its(:stdout) { should match /Win-PC/ }
end
````

serverspecの設定はひとまずここで完了。

# テスト対象ホストでWinRMを設定する。
WinRM(Windows Remote Management)は、HTTP/HTTPSでコンピュータをリモート管理するプロトコルで、serverspecからリモートのWindowsホストをテストする際も、WinRMでアクセスしてテストするのが一般的らしい。

まずは、管理者権限でpower shellを起動する。
「アクセサリ」->「Windows PowerShell」->「Windows PowerShell」を右クリックして「管理者として実行」をクリックし起動する。

以下のコマンドを発行し、WinRMの初期設定を行う。

````
PS C:\windows\system32> winrm qc
WinRM はこのコンピューター上で要求を受信するように設定されていません。
次の変更を行う必要があります:

WinRM サービスを開始します。

変更しますか [y/n]? y

WinRM は要求を受信するように更新されました。

WinRM サービスが開始されました。
このコンピュータ上のあらゆる IP への WS-Man 要求を受け付けるため、HTTP://* 上に WinRM リスナを作成します。

変更しますか [y/n]?

WinRM はリモート管理用に更新されました。

WinRM サービスの種類を正しく変更できました。 
WinRM サービスが開始されました。 
このコンピュータ上のあらゆる IP への WS-Man 要求を受け付けるため、HTTP://* 上に WinRM リスナを作成しました。
````

接続ネットワークに、PrivateもしくはDomain以外のものが存在する場合、以下のエラーが発生する。今回はVirtualBox Host-Only Networkが「識別されていないネットワーク」になっていた為、このエラーでハマってしまった。

````
Set-WSManQuickConfig : このコンピューターのネットワーク接続の種類の 1 つが Public に設定されているため、WinRM ファイアウォール例外は機能しません。 
ネットワーク接続の種類を Domain または Private に変更して、やり直してください。 
````

ローカル・セキュリティ・ポリシー等で設定可能なようだが、Windows7がHome Premiumである為使えず。。。なので、以下リンクの通りレジストリを修正して対応する。

http://27213143.at.webry.info/201207/article_1.html


次にBasic認証と暗号化していないメッセージを受けるけるよう設定する。
この設定を行っていないと、テスト実行時に401エラーが出てテストがfailになる。

````
PS C:\windows\system32> winrm set winrm/config/service/auth '@{Basic="true"}'
Auth
    Basic = true
    (略)
PS C:\windows\system32> winrm set winrm/config/service '@{AllowUnencrypted="true"}'
Service
    (略)
    AllowUnencrypted = true
    (略)
````

serverspec用のユーザーを作成する。コントロールパネルのユーザーアカウントから管理者権限をつけたユーザーを作成。

これでWinRMの設定は完了。

# serverspecを実行する。
実行する前に、ユーザー情報をspec_helper.rbに設定する。

````
$ vi spec/spec_helper.rb
$ cat spec/spec_helper.rb
require 'serverspec'
require 'winrm'

set :backend, :winrm

user = '（WIndowsユーザー名）'
pass = '（パスワード）'
endpoint = "http://#{ENV['TARGET_HOST']}:5985/wsman"

winrm = ::WinRM::WinRMWebService.new(endpoint, :ssl, :user => user, :pass => pass, :basic_auth_only => true)
winrm.set_timeout 300 # 5 minutes max timeout for any operation
Specinfra.configuration.winrm = winrm
````

テストを実行する。テスト通った。

````
bundle exec rake spec
/usr/local/rvm/rubies/ruby-1.9.3-p448/bin/ruby -S rspec spec/localhost/host_spec.rb
.

Finished in 0.64601 seconds
1 example, 0 failures
````

これでWindowsサーバのテストシナリオの実装が捗るぜ！