今年(2016年)になってからrubygemsのWinRMでインターフェース変更が激しく周りが追いついていない。
例えば現状(2016/10/28)、ServerspecでWindows相手にテスト実行する環境を整えてrake実行しても以下のようなエラーが出て止まってしまうわけですが、それを回避するためのメモ。
[root@alpha-139 ~]# rake
/usr/bin/ruby -I/usr/local/share/gems/gems/rspec-core-3.5.4/lib:/usr/local/share/gems/gems/rspec-support-3.5.0/lib /usr/local/share/gems/gems/rspec-core-3.5.4/exe/rspec --pattern spec/testw/\*_spec.rb
/root/spec/spec_helper.rb:10:in `<top (required)>': uninitialized constant WinRM::WinRMWebService (NameError)
1.spec/spec_helper.rb を修正する
spec/spec_helper.rb は serverspec-init を実行すると生成されるもので、現状(serverspec (2.37.2))では以下の様なものですが、まずはここから動かんです。
require 'serverspec'
require 'winrm'
set :backend, :winrm
user = <username>
pass = <password>
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
WinRM::WinRMWebServiceを、WinRM::Connectionを使用するように修正します。
require 'serverspec'
require 'winrm'
set :backend, :winrm
opts = {
user: "Administrator",
password: "password",
endpoint: "http://#{ENV['TARGET_HOST']}:5985/wsman",
operation_timeout: 300,
}
winrm = WinRM::Connection.new(opts)
Specinfra.configuration.winrm = winrm
(参考)github - WinRb/WinRM
https://github.com/WinRb/WinRM
2.backend/winrm.rb を修正する
あー、元のコードをすべて掲載するのは面倒くさいことであるので省略しますが、specinfra(現時点のバージョン 2.63.3)の一部のファイルも新しいgem/winrmの実装に追いついていないので(powershellというメソッドが廃止されて、shell(:powershell) になっているのに対応していない)、そちらも修正する必要があります。
ちなみに修正しないと以下様なエラーが出ます
1) Port "80" should be listening
On host `testw'
Failure/Error: it { should be_listening }
NoMethodError:
undefined method `powershell' for #<WinRM::Connection:0x00000003244ea8>
# /usr/local/share/gems/gems/specinfra-2.63.3/lib/specinfra/backend/winrm.rb:14:in `run_command'
# /usr/local/share/gems/gems/specinfra-2.63.3/lib/specinfra/runner.rb:27:in `run'
# /usr/local/share/gems/gems/specinfra-2.63.3/lib/specinfra/runner.rb:19:in `method_missing'
とりあえず、bashプロンプトで以下を実行すると修正されます(rubyコードそのものではないです)。
念のためオリジナルの winrm.rb を winrm.rb.org という名前でとっています。
pushd /usr/local/share/gems/gems/specinfra-*/lib/specinfra/backend
if [ ! -e winrm.rb.org ] ; then cp winrm.rb winrm.rb.org ; fi
cat > winrm.rb << 'EOF'
module Specinfra
module Backend
class Winrm < Base
include PowerShell::ScriptHelper
def os_info
{ :family => 'windows', :release => nil, :arch => nil }
end
def run_command(cmd, opts={})
script = create_script(cmd)
winrm = get_config(:winrm)
shell = winrm.shell(:powershell)
result = shell.run(script)
stdout = result.stdout
stderr = result.stderr
exit_status = result.exitcode
shell.close
if @example
@example.metadata[:command] = script
@example.metadata[:stdout] = stdout + stderr
end
CommandResult.new :stdout => stdout, :stderr => stderr, :exit_status => exit_status
end
end
end
end
EOF
popd
ちなみにspecinfraのgithubは以下ですが、フィードバックするのが手間なので親切な方がいれば是非・・
https://github.com/mizzy/specinfra
とはいえ、2016年はじめぐらいにgem/WinRMが認証プロトコルとして:negotiateに対応し始めたのですが、このおかげでWindows側にHTTPS/basic認証を有効にするとかの手間が要らなくなっており、これがそれなりにすばらしい。
この辺はAnsibleのためにpython/winrmでも早く実装してくれればと、