specinfraは汎用コマンド実行フレームワーク。RubyGemsとしてで配布されています。
追記:これは1の頃の話なので全体的に古いです。
この書籍が一番詳しい。 => O'Reilly Japan - Serverspec
ソースはこちら https://github.com/serverspec/specinfra
specinfraが目指す所は、情報処理学会研究報告の serverspec: 宣言的記述でサーバの状態をテスト可能な 汎用性の高いテストフレームワーク という論文を見ると良いでしょう。
論文もソースコードと同様にGithubに公開されています。
https://github.com/mizzy/serverspec-thesis
概要
同じメソッドで任意のOS用のコマンド実行文字列を取得したり実行して結果をとったりします。
さわった感じこんな挙動
- バックエンドの形式を選ぶ
- バックエンドを元にインスタンスを作成したら、あとは同じメソッドでどこでもOK
ローカルホストを対象に実行する
チュートリアルはありませんが、serverspecのソースといつものspec_helper.rb
を見れば大体つかめます。
require 'specinfra'
include SpecInfra::Helper::DetectOS
include SpecInfra::Helper::Exec
## exec(ローカル実行)をバックエンドにインスタンスを生成する
i = Backend.backend_for('exec')
## こんな感じで共通コマンドが実行できる
i.check_os
>> 追記1
specinfra開発mizzy/@gosukenatorさんによると、単純に使う場合はインスタンス作るまでもなかったようです。
@sawanoboly include SpecInfra::Helper::Exec してる場合は、バックエンドインスタンスを明示的に生成しなくても、https://t.co/HMFVbb2ehY こんな感じでいけますね。(serverspec はこのやりかたです。)
— Gosuke Miyashita (@gosukenator) 2014, 3月 13
こういう事、との事。
require 'specinfra'
include SpecInfra::Helper::DetectOS
include SpecInfra::Helper::Exec
backend.check_os
あらほんとだ。
> backend.check_os
=> {:family=>"Darwin", :release=>nil}
lib/specinfra/helper/backend.rbの動的なメソッド定義はそういうことだったのね。
<< 追記1
実行の様子
Pryから叩いてみます。
> i.check_os
=> {:family=>"Darwin", :release=>nil}
メソッドで成否判定をする場合はこんな感じ。
> i.check_resolvable('www.google.com', 'dns')
=> true
実行されるコマンドを取得する時は#commands
から同じことをすると良いみたいです。
> i.commands.check_resolvable('www.google.com', 'dns')
=> "nslookup -timeout=1 www.google.com"
確認しつつ実行とか。
> i.commands.check_file('/tmp')
=> "test -f /tmp"
> i.check_file('/tmp')
=> false
run_command
#run_command
で任意のコマンドを実行してくる事も可能。
これもバックエンドをちゃんと選択してくれます。
> i.run_command('ls')
=> #<SpecInfra::CommandResult:0x007fdd634b3640
@exit_signal=nil,
@exit_status=0,
@stderr="",
@stdout=
"Gemfile\nGemfile.lock\nGuardfile\nLICENSE.txt\nREADME.md\nRakefile\nci\nconfig\nenv.sh\nfeatures\njackalope\nlib\npast_features\nrake\nslayer_kitchen\nspec\ntmp\n">
メソッドの中には直接実行すると、次のように結果が期待しているのではなかったりします。
※これはUbuntuで実行してます
追記: ここのくだりは修正されています。
> i.get_package_version('tmux')
=> true
いやバージョン欲しいねんけど、って時にも#run_command
をかますといいのかもしれない?
追記:
check_*
以外はCommandResult
をそのまま返してくれるように変更されたので、get_package_version
の戻りがこの次のサンプルとおなじになります。
> i.commands.get_package_version('tmux')
=> "dpkg-query -f '${Status} ${Version}' -W tmux | sed -n 's/^install ok installed //p'"
> i.run_command(i.commands.get_package_version('tmux'))
=> #<SpecInfra::CommandResult:0x007fa0a2283cd8
@exit_signal=nil,
@exit_status=0,
@stderr="",
@stdout="1.6-1ubuntu1">
実行できるメソッド達
lib/specinfra/commandを参考にします。
たいていはBaseに定義されているので、ざっと眺めることも出来ます。
> SpecInfra::Command::Base.instance_methods(false)
=> [:escape,
:check_enabled,
:check_yumrepo,
:check_yumrepo_enabled,
:check_mounted,
:check_routing_table,
:check_reachable,
:check_resolvable,
:check_file,
:check_socket,
:check_directory,
:check_user,
:check_group,
:check_installed,
:check_service_installed,
:check_service_start_mode,
:check_listening,
:check_listening_with_protocol,
:check_running,
:check_running_under_supervisor,
:check_running_under_upstart,
:check_monitored_by_monit,
:check_monitored_by_god,
:check_process,
:get_process,
:check_file_contain,
:check_file_contain_with_regexp,
:check_file_contain_with_fixed_strings,
:check_file_checksum,
:check_file_md5checksum,
:check_file_sha256checksum,
:check_file_contain_within,
:check_mode,
:check_owner,
:check_grouped,
:check_cron_entry,
:check_link,
:check_installed_by_gem,
:check_installed_by_npm,
:check_installed_by_pecl,
:check_installed_by_pear,
:check_installed_by_pip,
:check_installed_by_cpan,
:check_belonging_group,
:check_gid,
:check_uid,
:check_login_shell,
:check_home_directory,
:check_authorized_key,
:check_iptables_rule,
:check_zfs,
:get_mode,
:check_ipfilter_rule,
:check_ipnat_rule,
:check_svcprop,
:check_svcprops,
:check_selinux,
:check_access_by_user,
:check_kernel_module_loaded,
:check_ipv4_address,
:check_mail_alias,
:get_file_content,
:check_container,
:check_cotainer_running,
:get_package_version]
SSH越しのホストを対象に実行する
コマンドをSSH越しに実行してくるには、SpecInfra.configuration.ssh
にNet::SSH.start
で作成されるインスタンスを入れておけば良いみたいです。
require 'specinfra'
require 'net/ssh'
include SpecInfra::Helper::DetectOS
include SpecInfra::Helper::Ssh
## コンフィグにNet::SSHのインスタンスを設定
# optionsの指定等はserverspecが作るspec_helperを参考にしましょう
SpecInfra.configuration.ssh = Net::SSH.start('example.com', 'root', {})
## sshをバックエンドにインスタンスを生成する
i = Backend.backend_for('ssh')
## こんな感じで共通コマンドが実行できる
i.check_os
> i.class
=> SpecInfra::Backend::Ssh
> i.check_os
=> {:family=>"Ubuntu", :release=>nil}
あとはもはやローカルと同じです。
i.commands.check_resolvable('www.google.com', 'dns')
=> "nslookup -timeout=1 www.google.com"
> i.commands.check_resolvable('www.google.com', nil)
=> "getent hosts www.google.com"
OSに合わせてメソッドの内容も調整されています。
この様子もlib/specinfra/commandで確認できます。
パッケージやサービスの確認をしてみました。
> i.commands.check_installed('nagios3')
=> "dpkg-query -f '${Status}' -W nagios3 | grep '^install ok installed$'"
> i.check_installed('nagios3')
=> true
> i.check_running('nagios3')
=> true
> i.commands.check_running('nagios3')
=> "service nagios3 status && service nagios3 status | grep 'running'"
おわりに
今回はRSpecではなく、他のテストフレームワークから似たようなことをするためにspecinfraをさわってみました。
目的がテストだと、結局serverspecみたいになりますね。