More than 1 year has passed since last update.

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さんによると、単純に使う場合はインスタンス作るまでもなかったようです。

こういう事、との事。

gist.github.com/mizzy/9521892
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.sshNet::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みたいになりますね。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.