前書き
Serverspecを実務で使うとなると、標準のResource TypeとMatcherだけでは足りず、どうしてもカスタマイズ(拡張)を避けられないと思います。
"command"リソースタイプと、Matcherで正規表現を使えば、ほとんどの場合対応可能でしょうが、どういう時にResource Typeを追加するかは少し悩ましいかもしれません。ここのテストで使ったResource Typeの追加方法を記載します。参考にしたのは、本家のこの本です。
宮下 剛輔 (著) Serverspec
この本に書かれていますが、フロントエンドのServerspec側の対応と、テスト対象ホストに対して実際にコマンドを発行するSpecinfra側の対応が必要になります。
Serverspec 側の拡張
Resource Typeの追加
配列 "types" に "locale" と "timezone" を追記
serverspec/helper/type.rb
module Serverspec
module Helper
module Type
types = %w(
base bridge bond cgroup command cron default_gateway file fstab
group host iis_website iis_app_pool interface ipfilter ipnat
iptables ip6tables json_file kernel_module kvm linux_kernel_parameter lxc
mail_alias mysql_config package php_config port ppa process
routing_table selinux selinux_module service user yumrepo
windows_feature windows_hot_fix windows_registry_key
windows_scheduled_task zfs docker_base docker_image
docker_container x509_certificate x509_private_key
linux_audit_system hadoop_config php_extension windows_firewall
locale timezone
)
types.each {|type| require "serverspec/type/#{type}" }
types.each do |type|
define_method type do |*args|
eval "Serverspec::Type::#{type.to_camel_case}.new(*args)"
end
end
end
end
end
以下のファイルを作成
serverspec/type/locale.rb
module Serverspec::Type
class Locale < Base
def value
str = "#{name}".split.last
ret = @runner.run_command("/bin/localectl status | grep #{str}")
val = ret.stdout.split(':').last.strip
end
end
end
serverspec/type/timezone.rb
module Serverspec::Type
class Timezone < Base
def value
ret = @runner.run_command("/bin/timedatectl status | grep 'zone' ")
val = ret.stdout.split(':').last.strip
val = val.split(' ').first
end
end
end
今回、Matcherの追加は行いませんでした。
Specinfra 側の拡張
以下のファイルを作成
specinfra/command/base/locale.rb
class Specinfra::Command::Base::Locale < Specinfra::Command::Base
end
specinfra/command/base/timezone.rb
class Specinfra::Command::Base::Timezone < Specinfra::Command::Base
end
以上