App::RemoteCommand リリース
App::RemoteCommand というのを cpan にあげた。
- cpan: https://metacpan.org/release/App-RemoteCommand
- github: https://github.com/shoichikaji/App-RemoteCommand
インストール方法
> cpanm App::RemoteCommand
> rcommand -v
App::RemoteCommand 0.01
なにするもの?
ssh で複数ホストにはいって並列にコマンドを実行するスクリプト。
なんで作ったか
fabric や chef を使えば複数ホストに並列にコマンドを実行できる。 が、専用のシンタックスで書かなくちゃいけないしイマイチカジュアルじゃない。
ssh
, xargs
を組み合わせて
> cat host-list.txt | xargs -P5 -L1 -I{} ssh {} 'uname -a'
というのもできるが、いろいろめんどくさい。
もっと直感的に扱えるのが欲しかった。
特徴
App::RemoteCommand およびそのフロントエンド rcommand
の特徴は
- 複数ホストに並列にコマンドを実行できる。
- 複数ホストをいい感じに指定できる。
- sudo password を最初に覚えておいて、以後自動で補完してくれる。
- ローカルにあるスクリプトを直接指定できる。
- コマンド出力に実行したホスト名、時刻をつけてくれる。
- 最後にどのホストで成功したか、失敗したかのサマリーがでる。
使い方
基本
基本的には ssh HOST COMMAND
と同じで
> rcommand HOSTS COMMAND
とする。( 現状の実装では ssh は no pass で通る前提になっているので
もし ssh 鍵の password が必要な場合は事前に ssh-agent
をあげておく。)
例えば www001.example.com
に uname
コマンドを実行したい時は
> rcommand www001.example.com uname
[www001.example.com] Linux
SUCCESS www001.example.com
でいい。さらに www002.example.com
にも実行したいなら
> rcommand 'www001.example.com,www002.example.com' uname
[www001.example.com] Linux
[www002.example.com] Linux
SUCCESS www001.example.com
SUCCESS www002.example.com
でいい。実際は、連番のホストに実行したいなら [*-*]
という記法が使えるので
> rcommand 'www[001-002].example.com' uname
[www001.example.com] Linux
[www002.example.com] Linux
SUCCESS www001.example.com
SUCCESS www002.example.com
でOK。またデータセンター別にホスト名を変えている場合などは {*,*}
という記法が使えるので、
> rcommand 'www001.example.{com,jp,us}' uname
[www001.example.com] Linux
[www001.example.us] Linux
[www001.example.jp] Linux
SUCCESS www001.example.us
SUCCESS www001.example.com
SUCCESS www001.example.jp
とできる。もちろん [*-*]
, {*,*}
は同時に使えて
> rcommand 'www00[1-2].example.{com,jp}' 'uname -a'
...
も可能。ちなみにこのホスト名展開は String::Glob::Permute を使ってる。
ローカルスクリプト実行
実行するコマンドをワンライナーで書くのは時に面倒。 その場合はローカルでスクリプトを書いてそれを指定すればいい。
> cat local-script.sh
#!/bin/bash
percent=`df -h | grep /dev/sda1 | perl -anle '$F[-2] =~ s/%//; print $F[-2]'`
if [ $percent -lt 80 ]; then
echo "OK $percent%"
else
echo "NG $percent%"; exit 1
fi
> rcommand --script local-script.sh 'www00[1-2].example.jp'
[www002.example.jp] OK 65%
[www001.example.jp] NG 85%
SUCCESS www002.example.jp
FAIL www001.example.jp
また、上記のように最後にSUCCESS/FAIL のサマリーが出て どのホストで成功したか、失敗したがわかるようになってる。
sudo password
sudo
が入っているコマンドを実行する場合、--ask-sudo-password
オプションを指定し実行すると、最初にプロンプトが出てきてそこで sudo password
を記憶し、以後自動で補完してくれる。
> rcommand --ask-sudo-password 'www00[1-2].example.jp' 'sudo service cron restart'
sudo password (asking with rcommand):
[www002.example.jp] sudo password (asking with rcommand):
[www002.example.jp]
[www001.example.jp] sudo password (asking with rcommand):
[www001.example.jp]
[www002.example.jp] cron stop/waiting
[www002.example.jp] cron start/running, process 7416
...
その他
[*-*]
, {*,*}
を使えばだいたい対象ホストをいい感じで指定できると思うが、
時にファイルに書いたホストを対象としたい時があるかもしれない。
そんな時は --host-file
が使える。
> cat host.txt
# comment
www001.example.jp
www002.example.com
> rcommand --host-file host.txt 'w | head -n1'
[www002.example.com] 15:35:11 up 2:00, 1 user, load average: 0.00, 0.01, 0.05
[www001.example.jp] 15:35:12 up 2:00, 2 users, load average: 0.03, 0.03, 0.05
...
--append-time
を指定すれば各出力に時刻がつく。
> rcommand --append-time www001.example.jp 'echo 1; sleep 1; echo 2'
[2015-01-05 00:36:58][www001.example.jp] 1
[2015-01-05 00:36:59][www001.example.jp] 2
...
デフォルトで各出力につくホスト名が邪魔なら --no-append-hostname
を指定すればいい。
> rcommand --no-append-hostname www001.example.jp 'uname -a'
Linux vagrant-ubuntu-trusty-64 3.13.0-30-generic #55-Ubuntu SMP Fri Jul 4 21:40:53 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
SUCCESS www001.example.jp
デフォルトだと rcommand
は 5並列でコマンドを実行しようとする。
これを変えたい場合は --concurrency
で指定すればいい。
> rcommand --concurrency 1 -a 'www00[1-3].example.{jp,com}' sudo service httpd stop
...
よくわからなくなったら rcommand --help
とすればなんかでてくるはず。
TODO
- コマンドの stdout/stderr が区別できず全部 stdout になってる。
- 1 host あたり 3 process fork するのをなんとかしたい。
- シグナルハンドリングがよくわかってない。
- IO::Prompter を使いこなせない。
- 特に多段sshをしてるとき、
Input/output error
(errno 5?) のエラーがでるときがある。