AnsilbleSpecでWindowsServerをテストする

ここで作成したspec/spec_helper.rbでは、Windowsマシンテスト時にハングする等不具合があった。

判明している対Windowsでの不具合は以下の通り。

  1. テストケースが完了しない(タイムアウト)。TCP/5986でESTABLISHにはなっている
  2. 変数でダンプしているのにログインユーザ・パスワードを聞いてくる
  3. WinRM::WinRMWebServiceを使うなというエラー

最終的にはいずれも解決し、正常に動作するようになった。

1. テストケースが完了しない(タイムアウト)。TCP/5986でESTABLISHにはなっている

参考にしたサイトの多くでは、HTTPでエンドポイントが設定されおり、それをそのまま参照してしまったのが問題。
AnsibleではHTTPSが普通だが、ServerSpecではHTTPが普通っぽい。文化の違い。

2. 変数でダンプしているのにログインユーザ・パスワードを聞いてくる

spec_helper.rbで、読み込んだspec_varsを元にvarsを更新していなかった(コードの書き間違い)。

3. WinRM::WinRMWebServiceを使うなというエラー

こちらにも書かれている通り、最近はWinRM::Connectionを使うのが普通らしい。
同じ接続になるよう、パラメータを調整し書き換える。
ただし、今回はHTTPSで接続するのでno_ssl_peer_verificationを入れないと、正規証明書でない場合に接続エラーになるので
このパラメータを新たに追加する。

修正したspec/spec_helper.rb

require 'serverspec'
require 'ansible_spec'
require 'net/ssh'
require 'winrm'
require 'yaml'

#
# Set ansible variables to serverspec property
#
host = ENV['TARGET_HOST']
hosts = ENV["TARGET_HOSTS"]

group_idx = ENV['TARGET_GROUP_INDEX'].to_i
vars = AnsibleSpec.get_variables(host, group_idx, hosts)
ssh_config_file = AnsibleSpec.get_ssh_config_file
if ENV['TARGET_HOST_VARS_PATH'].nil?
  set_property vars
else
  # 環境変数"TARGET_HOST_VARS_PATH"でホスト毎の変数ファイルを指定する必要がある
  host_vars = YAML.load_file(ENV['TARGET_HOST_VARS_PATH'])
  set_property vars.update(host_vars)
end

connection = ENV['TARGET_CONNECTION']

case connection
when 'ssh'
#
# OS type: UN*X
#
  set :backend, :ssh

  if ENV['ASK_BECOME_PASSWORD']
    begin
      require 'highline/import'
    rescue LoadError
      fail "highline is not available. Try installing it."
    end
    set :become_password, ask("Enter become password: ") { |q| q.echo = false }
  else
    set :become_password, ENV['BECOME_PASSWORD']
  end

  options = Net::SSH::Config.for(host)

  options[:user] = ENV['TARGET_USER'] || vars['ansible_user'] || options[:user]
  options[:port] = ENV['TARGET_PORT'] || vars['ansible_port'] || options[:port]
  options[:keys] = ENV['TARGET_PRIVATE_KEY'] || options[:keys]

  if ssh_config_file
    from_config_file = Net::SSH::Config.for(host,files=[ssh_config_file])
    options.merge!(from_config_file)
  end

  set :host,        options[:host_name] || host
  set :ssh_options, options

  # Disable become
  # set :become, false


  # Set environment variables
  # set :env, :LANG => 'C', :LC_MESSAGES => 'C'

  # Set PATH
  # set :path, '/sbin:/usr/local/sbin:$PATH'
when 'winrm'
#
# OS type: Windows
#
  set :backend, :winrm
  set :os, :family => 'windows'

  user = ENV['TARGET_USER'] || vars['ansible_user']
  port = ENV['TARGET_PORT'] || vars['ansible_port']
  pass = ENV['TARGET_PASSWORD'] || vars['ansible_password']

  if user.nil?
    begin
      require 'highline/import'
    rescue LoadError
      fail "highline is not available. Try installing it."
    end
    user = ask("\nEnter #{host}'s login user: ") { |q| q.echo = true }
  end
  if pass.nil?
    begin
      require 'highline/import'
    rescue LoadError
      fail "highline is not available. Try installing it."
    end
    pass = ask("\nEnter #{user}@#{host}'s login password: ") { |q| q.echo = false }
  end

  endpoint = "https://#{host}:#{port}/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
  # https://qiita.com/rk05231977/items/d4b05f7c92631be79d53
  # https://github.com/WinRb/WinRM
  winrm = WinRM::Connection.new(
    endpoint: endpoint,
    transport: :ssl,
    no_ssl_peer_verification: true,
    user: user,
    password: pass,
    basic_auth_only: true,
    operation_timeout: 300
  )
  Specinfra.configuration.winrm = winrm

when 'local'
#
# local connection
#
    set :backend, :exec
end

no_ssl_peer_verificationのtrue/falseをvars[‘ansible_winrm_server_cert_validation’]から判定してもいいかも。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です