はじめに
前に書いた記事Serverspecでロジックとテストケースの分離を検討してみたの続きです。
テストケース
YAMLファイルにチェックしたい内容を記載します。
今回はapacheを例に取り上げました。
$TEST_HOME\sample\env\apache_conf.yml
# チェック内容
CONF:
# ファイル内容の確認
FILE:
httpd.conf:
PATH: C:\APP\Apache\etc\httpd\conf\httpd.conf
STATUS: true
MATCH:
Server:
- ServerRoot "C:/APP/Apache/etc/httpd"
- ServerTokens ProductOnly
- ServerSignature Off
PidFile:
- PidFile run/httpd.pid
Timeout:
- Timeout 120
KeepAlive:
- KeepAlive Off
Include:
- Include conf.d/*.conf
LogFormat:
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined_time
LoadModule:
- LoadModule authz_host_module modules/mod_authz_host.so
- LoadModule log_config_module modules/mod_log_config.so
- LoadModule deflate_module modules/mod_deflate.so
- LoadModule headers_module modules/mod_headers.so
UNMATCH:
LoadModule:
- LoadModule auth_digest_module modules/mod_auth_digest.so
- LoadModule authn_alias_module modules/mod_authn_alias.so
# レジストリ登録内容の確認
REGISTRY:
service:
PATH: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Apache2.2
STATUS: true
MATCH:
type_string:
DisplayName: Apache2.2
type_dword:
Type: 16
type_expandstring:
ImagePath: \"C:\APP\Apache\bin\httpd.exe\" -k runservice
# ホスト毎のチェック項目マッピング
STG-WEB01:
FILE:
- httpd.conf
REGISTRY:
- service
STG-WEB02:
FILE:
- httpd.conf
REGISTRY:
- service
ファイル内容をチェックするspecファイル
specファイルからyamlファイルを読み込み、現在のサーバのテスト内容を判別して評価します。
$TEST_HOME\sample\spec\apache\apache_conf_spec.rb
require 'spec_helper'
require 'yaml'
require 'CmnClsHelper'
objHelper = CmnClsHelper.new
this_file_name = File.basename( __FILE__, ".rb" )
this_file_dir_path = File.dirname( File.expand_path( __FILE__ ) )
this_parent_name = File.basename( this_file_dir_path )
target_host = "#{ENV['TARGET_HOST']}".upcase
this_yaml_name = this_file_name.gsub("_spec", "")
path_f_yml = "env/#{this_yaml_name}.yml"
strHR = "=" * 60
path_d_parser = "C:\\Tool\\Infra\\serverspec\\parser"
path_d_cmd = "C:\\Tool\\Infra\\serverspec\\cmd"
puts "PATH_F_YAML = #{path_f_yml}"
h_all = YAML.load_file(path_f_yml)
if h_all.key?(target_host) && h_all["CONF"] && h_all["CONF"].instance_of?( Hash )
check_file_list = []
h_replace_list = {}
target_category = "FILE"
if h_all["#{target_host}"].instance_of?( Hash ) && h_all["#{target_host}"]["#{target_category}"]
if h_all["#{target_host}"]["#{target_category}"].instance_of?( Array )
h_all["#{target_host}"]["#{target_category}"].each do |filename|
check_file_list << filename
end
end
end
if h_all["#{target_host}"].instance_of?( Hash ) && h_all["#{target_host}"]["REPLACE"]
if h_all["#{target_host}"]["REPLACE"].instance_of?( Hash )
h_all["#{target_host}"]["REPLACE"].each do |target_var_name, h_val|
h_replace_list["#{target_var_name}"] = {} if ! h_replace_list.key?("#{target_var_name}")
h_val.each do |replace_key, replace_val|
h_replace_list["#{target_var_name}"]["#{replace_key}"] = "#{replace_val}"
end
end
end
end
if h_all["CONF"]["#{target_category}"] && h_all["CONF"]["#{target_category}"].instance_of?( Hash )
check_file_list.each do |target_name|
context "#{strHR}\n[#{target_host}] #{this_parent_name}/#{this_file_name} : #{target_name}\n#{strHR}\n" do
if h_all["CONF"]["#{target_category}"]["#{target_name}"] && h_all["CONF"]["#{target_category}"]["#{target_name}"].instance_of?( Hash )
h_cur_test_case = h_all["CONF"]["#{target_category}"]["#{target_name}"]
ary_ignore_spaces = []
h_check_list = {}
blnIsPipeParse = false
cmd_parser = ""
path_f_taget = "NOT_DEFINED"
path_f_taget = h_cur_test_case["PATH"] if h_cur_test_case["PATH"]
if h_replace_list["PATH"] && h_replace_list["PATH"].instance_of?( Hash )
h_replace_list["PATH"].each do |replace_key, replace_val|
path_f_taget = path_f_taget.gsub("#{replace_key}","#{replace_val}")
end
end
if h_cur_test_case.key?("PIPE-PARSE") && objHelper.isNotNull(h_cur_test_case["PIPE-PARSE"])
blnIsPipeParse = true
case File.extname(h_cur_test_case["PIPE-PARSE"])
when ".rb" then
cmd_parser = "ruby #{path_d_parser}\\#{h_cur_test_case['PIPE-PARSE'].strip}"
else
cmd_parser = "#{path_d_parser}\\#{h_cur_test_case['PIPE-PARSE'].strip}"
end
end
if h_cur_test_case.key?("STATUS")
stat_f_taget = h_cur_test_case["STATUS"]
describe file("#{path_f_taget}") do
if stat_f_taget
it { should be_file }
else
it { should_not be_file }
end
end
end
if h_cur_test_case.key?("IGNORE_MULTI_SPACES") && h_cur_test_case["IGNORE_MULTI_SPACES"].instance_of?( Array )
ary_ignore_spaces = h_cur_test_case["IGNORE_MULTI_SPACES"]
end
["MATCH", "UNMATCH","MATCH-REGEX", "UNMATCH-REGEX", "FILE-MATCH", "FILE-UNMATCH", "FILE-MATCH-REGEX", "FILE-UNMATCH-REGEX"].each do |check_action|
blnIsCmd = true
blnIsMatch = true
blnIsUseRegex = false
action = "MATCH"
if h_cur_test_case[check_action] && h_cur_test_case[check_action].instance_of?( Hash )
case "#{check_action}"
when "FILE-MATCH"
blnIsCmd = false
when "FILE-MATCH-REGEX"
blnIsCmd = false
blnIsUseRegex = true
when "FILE-UNMATCH"
blnIsCmd = false
blnIsMatch = false
action = "UNMATCH"
when "FILE-UNMATCH-REGEX"
blnIsCmd = false
blnIsMatch = false
blnIsUseRegex = true
action = "UNMATCH"
when "MATCH-REGEX"
blnIsUseRegex = true
when "UNMATCH-REGEX"
blnIsMatch = false
blnIsUseRegex = true
action = "UNMATCH"
when "UNMATCH"
blnIsMatch = false
action = "UNMATCH"
end
h_cur_test_case[check_action].each do |filter_name, ary_case|
# 器の用意
h_check_list["#{filter_name}"] ||= {}
h_check_list["#{filter_name}"]["MATCH"] ||= []
h_check_list["#{filter_name}"]["UNMATCH"] ||= []
h_check_list["#{filter_name}"]["CMD"] = blnIsCmd
#
ary_case.each do |test_case|
blnIsIgnoreSpaces = ary_ignore_spaces.include?(filter_name) ? true : false
tmp = objHelper.convCheckStr({"str" => "#{test_case}".strip, "blnIsUseRegex" => blnIsUseRegex, "blnIsIgnoreSpaces" => blnIsIgnoreSpaces})
tmp = "#{tmp}".encode("Windows-31J")
h_check_list["#{filter_name}"]["#{action}"] << "#{tmp}" if "#{tmp}" != ""
end
end
end
end
h_check_list.each do |filter_name, h_case|
if h_case["CMD"]
# 「|」で日本語が化けるため、バッチを用意(バッチ内の「|」だと日本語が化けない)
exec_cmd = "#{path_d_cmd}\\cat.cmd #{path_f_taget}"
if blnIsPipeParse
if "#{filter_name}".upcase != "NO_GREP"
exec_cmd = "#{path_d_cmd}\\cat_parser_grep.cmd #{path_f_taget} #{filter_name} #{cmd_parser}"
else
exec_cmd = "#{path_d_cmd}\\cat_parser.cmd #{path_f_taget} #{cmd_parser}"
end
else
if "#{filter_name}".upcase != "NO_GREP"
exec_cmd = "#{path_d_cmd}\\cat_grep.cmd #{path_f_taget} #{filter_name}"
end
end
# ファイル内容出力コマンド
describe command("#{exec_cmd}") do
h_case["MATCH"].each do |test_case|
its(:stdout) { should match /#{test_case}/ }
end
h_case["UNMATCH"].each do |test_case|
its(:stdout) { should_not match /#{test_case}/ }
end
end
else
describe file("#{path_f_taget}") do
h_case["MATCH"].each do |test_case|
its(:content) { should match /#{test_case}/ }
end
h_case["UNMATCH"].each do |test_case|
its(:content) { should_not match /#{test_case}/ }
end
end
end
end
end
end
end
end
end
レジストリ設定内容をチェックするspecファイル
specファイルからyamlファイルを読み込み、現在のサーバのテスト内容を判別して評価します。
$TEST_HOME\sample\spec\apache\apache_registry_spec.rb
require 'spec_helper'
require 'yaml'
require 'CmnClsHelper'
objHelper = CmnClsHelper.new
this_file_name = File.basename( __FILE__, ".rb" )
this_file_dir_path = File.dirname( File.expand_path( __FILE__ ) )
this_parent_name = File.basename( this_file_dir_path )
target_host = "#{ENV['TARGET_HOST']}".upcase
path_f_yml = "env/apache_conf.yml"
strHR = "=" * 60
h_all = YAML.load_file(path_f_yml)
if h_all.key?(target_host) && h_all["CONF"] && h_all["CONF"].instance_of?( Hash )
check_target_list = []
target_category = "REGISTRY"
if h_all["#{target_host}"].instance_of?( Hash ) && h_all["#{target_host}"]["#{target_category}"]
if h_all["#{target_host}"]["#{target_category}"].instance_of?( Array )
h_all["#{target_host}"]["#{target_category}"].each do |target_name|
check_target_list << target_name
end
end
end
if h_all["CONF"]["#{target_category}"] && h_all["CONF"]["#{target_category}"].instance_of?( Hash )
check_target_list.each do |target_name|
context "#{strHR}\n[#{target_host}] #{this_parent_name}/#{this_file_name} : #{target_name}\n#{strHR}\n" do
if h_all["CONF"]["#{target_category}"]["#{target_name}"] && h_all["CONF"]["#{target_category}"]["#{target_name}"].instance_of?( Hash )
h_cur_test_case = h_all["CONF"]["#{target_category}"]["#{target_name}"]
path_f_taget = "NOT_DEFINED"
path_f_taget = h_cur_test_case["PATH"] if h_cur_test_case["PATH"]
if h_cur_test_case.key?("STATUS")
stat_f_taget = h_cur_test_case["STATUS"]
describe windows_registry_key("#{path_f_taget}") do
if stat_f_taget
it { should exist }
else
it { should_not exist }
end
end
end
["MATCH", "UNMATCH"].each do |check_action|
if h_cur_test_case[check_action] && h_cur_test_case[check_action].instance_of?( Hash )
blnIsMatch = true
blnIsMatch = false if check_action == "UNMATCH"
describe windows_registry_key("#{path_f_taget}") do
h_cur_test_case[check_action].each do |reg_type, h_list|
h_list.each do |key,val|
case reg_type
when "type_dword"
else
val = "#{val}".gsub("\\\"","_DQ_").gsub("_DQ_","\"")
end
case reg_type
when "type_string"
if blnIsMatch
it { should have_property("#{key}", :type_string) }
it { should have_property_value("#{key}", :type_string, "#{val}") }
else
it { should_not have_property("#{key}", :type_string) }
it { should_not have_property_value("#{key}", :type_string, "#{val}") }
end
when "type_dword"
if blnIsMatch
it { should have_property("#{key}", :type_dword) }
it { should have_property_value("#{key}", :type_dword, "#{val.to_s(16)}") }
else
it { should_not have_property("#{key}", :type_dword) }
it { should_not have_property_value("#{key}", :type_dword, "#{val.to_s(16)}") }
end
when "type_binary"
if blnIsMatch
it { should have_property("#{key}", :type_binary) }
it { should have_property_value("#{key}", :type_binary, "#{val}") }
else
it { should_not have_property("#{key}", :type_binary) }
it { should_not have_property_value("#{key}", :type_binary, "#{val}") }
end
when "type_qword"
if blnIsMatch
it { should have_property("#{key}", :type_qword) }
it { should have_property_value("#{key}", :type_qword, "#{val}") }
else
it { should_not have_property("#{key}", :type_qword) }
it { should_not have_property_value("#{key}", :type_qword, "#{val}") }
end
when "type_multistring"
if blnIsMatch
it { should have_property("#{key}", :type_multistring) }
it { should have_property_value("#{key}", :type_multistring, "#{val}") }
else
it { should_not have_property("#{key}", :type_multistring) }
it { should_not have_property_value("#{key}", :type_multistring, "#{val}") }
end
when "type_expandstring"
if blnIsMatch
it { should have_property("#{key}", :type_expandstring) }
it { should have_property_value("#{key}", :type_expandstring, "#{val}") }
else
it { should_not have_property("#{key}", :type_expandstring) }
it { should_not have_property_value("#{key}", :type_expandstring, "#{val}") }
end
end
end
end
end
end
end
end
end
end
end
end
実行
実行してみます。
PS C:\serverspec\sample> rake
##################################################
HOST: REMOTEHOST : development
##################################################
PATH_F_YAML = env/apache_conf.yml
============================================================
[REMOTESERVER] apache/apache_conf_spec : httpd.conf
============================================================
File "C:\APP\Apache\etc\httpd\conf\httpd.conf"
should be file
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf Server"
stdout
should match /ServerRoot \"C:\/APP\/Apache\/etc\/httpd\"/
stdout
should match /ServerTokens ProductOnly/
stdout
should match /ServerSignature Off/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf PidFile"
stdout
should match /PidFile run\/httpd\.pid/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf Timeout"
stdout
should match /Timeout 120/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf KeepAlive"
stdout
should match /KeepAlive Off/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf Include"
stdout
should match /Include conf\.d\/\*\.conf/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf LogFormat"
stdout
should match /LogFormat \"%h %l %u %t \\\"%r\\\" %>s %b \\\"%\{Referer\}i\\\" \\\"%\{User\-Agent\}i\\\" %D\" combined_time/
Command "C:\Tool\Infra\serverspec\cmd\cat_grep.cmd C:\APP\Apache\etc\httpd\conf\httpd.conf LoadModule"
stdout
should match /LoadModule authz_host_module modules\/mod_authz_host\.so/
stdout
should match /LoadModule log_config_module modules\/mod_log_config\.so/
stdout
should match /LoadModule deflate_module modules\/mod_deflate\.so/
stdout
should match /LoadModule headers_module modules\/mod_headers\.so/
stdout
should not match /LoadModule auth_digest_module modules\/mod_auth_digest\.so/
stdout
should not match /LoadModule authn_alias_module modules\/mod_authn_alias\.so/
============================================================
[REMOTESERVER] apache/apache_registry_spec : service
============================================================
Windows registry key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Apache2.2"
should exist
Windows registry key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Apache2.2"
should have property "DisplayName", :type_string
should have property value "DisplayName", :type_string, "Apache2.2"
should have property "Type", :type_dword
should have property value "Type", :type_dword, "16"
should have property "ImagePath", :type_expandstring
should have property value "ImagePath", :type_expandstring, "\"C:\\APP\\Apache\\bin\\httpd.exe\" -k runservice"
Finished in 49.38 seconds (files took 1.82 seconds to load)
132 examples, 0 failures ← テストケースは記事作成に際して一部削除してます。
##################################################
PS C:\serverspec\sample>