"shove" というシェルスクリプト用のテストツールを作った
CONTENTS:
"shove" とは
こちらです。
動作イメージとしては README.md にも貼っているスクリーンショットがわかりやすいと思うので、こちらにも貼ります。
成功時:
失敗時:
上のようにテストスクリプトを引数に与えて shove
コマンドを実行すると、テストを実行して結果を出力してくれます。
Perl Monger のみなさんは「proveっぽい」と思っていただけたでしょうか。
そうです。名前の "shove" は "shell" + "prove" を縮めたものです。
bash だけでなく、ksh, dash, zsh など POSIX を満たしているシェルに対応できるように作りました。
$SHELL
変数の値と異なるシェルでテストを実行したい場合は、 shove -s|--shell シェル
という形で指定してください。
Motivation
一言で言って、きっかけは Yak Shaving です。
最初に「シェルスクリプトのテストを書きたい」と思ったのは、PATH 操作ツール sh-pathctl を作ったときで、2週間ほど前のことでした。
pathctl は元々 Bash で使うことしか考えてなかったこともあり*1、最初に見つけたのは Bats でした。作者の sstephenson は rbenv の作者でもあり、rbenv も Bats でテストされているようです。
Bats のテストコードでは、@test "description" { ... }
で括った ...
部分の Bash コードが1つのテストケースとなり、set -e
で実行して 1行でも失敗したら FAIL というものです。
シンプルですが、まあこれで十分かな、という感じで、しばらくこれを使いました。
ところが、その後、思いつきでシェルスクリプトのパッケージ管理システムみたいなものを作りたくなり、実際に今 clenv というリポジトリで作っています。*2
…で、そのテストを Bash 以外でもやりたくなりました。
Bash 以外でも使えるテストツールを探してみたところ、思ったより色々あるようです。見つけたものを下に列挙します。
- shpec ... RSpec っぽくテストを書けるもの。まだ試してはいませんが、shove よりコードがきれいで筋がよさそうに見えます^^;
- shUnit2
- Sharness
- README の #alternatives にその他のテストツールが紹介されています。
- いくつかの TAP Producer ... Sharness の他にもいくつか紹介されています。
shUnit2 を少し試してみましたが、なんだか面倒であまり使い続ける気になりませんでした。
Sharness は README を見て、インタフェースにうーんとなってしまいました。
そんなに大したことをしたいわけでもないので、自作でも行けるだろう、と思って作り始め、まあそれなりに使えるものになったかな、というところです。
こんなツールにしたい
設計意図のようなものを下に並べます。
- テストコードをシェルスクリプトの文法で書きたい
- テストツールに余計なことをしてほしくない。書いた通りに動いてほしい
- 関連するテストをグループ化したい
何やってるのかわからなくて学習コストの高いテストフレームワークは嫌だな、と思っています。*3
今のところ、中で少し面倒な変換をしているところもあるのですが、概ね上に挙げたことは実現できているかと思っています。
使い方について
README.md#Usage で一通り網羅できているかと思います。
1つ、具体例を書いてみましょう。
下のようなシェルスクリプトがあったとします。
# add.sh add() { eval tmp=$"$1" eval $1=$(expr $tmp + $2) unset tmp }
テストコードは、例えば下のように書けます。
# add.t . add.sh var=3 t_ok $var "var" T_SUB "add A <num>" (( add var 3 t_is $var 6 "3 + 3 = 6" add var 5 t_is $var 11 "6 + 5 = 11" )) t_is $var 3 "subtest doesn't affect main context"
テストを実行すると下のようになります。
% shove add.t -v Run tests by /bin/zsh ------------------------- add.t ... ok 1 - var # add A <num> ok 1 - 3 + 3 = 6 ok 2 - 6 + 5 = 11 1..2 ok 2 - "add A <num>" ok 3 - subtest doesn't affect main context 1..3 ok Test Summary Report ------------------- All tests successful. Files=1, Tests=3, Successes=3, Failures=0 Result: PASS
中で何をやっているのか
shove foo.t bar.t
を実行すると、下のようなことを実行します。
foo.t
bar.t
を元に、それぞれテストスクリプトを$SHOVE_WORKDIR
(デフォルトは$HOME/.shove
) に生成します。- 先頭に以下の2行を足します。
. /path/to/shove/lib/t.shrc
...lib/t.shrc
にテスト用の関数が定義されています。t_init
... 初期化処理関数
- 末尾に
t_report $datfile
という行を足します。$datfile
にはテストの総数、成功数、失敗数が記録されます。 T_SUB "subtest name" ((
や))
という行を発見すると、テストをグループ化するコードに変換します。
- 先頭に以下の2行を足します。
- 生成したテストスクリプトを実行します。
- それぞれの
$datfile
のデータを集計します。 - 総テスト結果を表示します。
おわりに
自作のテストツール "shove" の紹介をしました。
機会がありましたら、どうぞご利用ください。
また、使ってみて何かトラブルがありましたら、GitHub Issuesなどでお知らせ下さい。
それでは、Have Fun!
渋谷.rb で "fireap" という pull 型デプロイツールの話をした #shibuyarb
拙作の fireap について、最初のお披露目記事(↓)を書いてから1ヶ月と少しが経ちました。
それから Ruby 系の勉強会に参加する機会を伺っていたのですが、ようやく昨日 4/20 に 渋谷.rb[:20160420] で少し話すことができました。
下がその発表スライドになります。
概要の紹介 + 直近(といっても1ヶ月前)の更新内容をざっくり話した感じです。
以下、前回記事からの差分という形でまとめます。
- v0.1 〜 v0.4 の更新内容
- Consul の "service" や "tag", ノード名でタスクの対象を選べるようにしました。
- config ファイルを毎コマンド実行前にバリデーションするようにしました。おかしな動作をしないように。
fireap task
というコマンドで config に定義したタスクを一覧表示できるようにしました。
- ドキュメントを GitHub Wiki に書きました。*1
「最低限必要そうな機能はあって、使ってみるのに足りる情報はある」状態にできているかな、と思っています。
もし試してみて動かないなどあれば、GitHub Issue なりでお知らせください。
渋谷.rb[:20160420] について
初めて Ruby の勉強会に参加しました。
昼間イベントページを見たとき 40 人中 20人弱ぐらいで、過疎らないかちょっと心配だったのですが、出席の人はだいたいいらっしゃっていた様子でした。
アットホームな感じでよかったです。
飲み会に行けなかったですが、若い人から SI 業の方まで色んな方がいらっしゃって、刺激になりました。
今後もときどき、どこかの Ruby の勉強会にお邪魔するかもしれません。
どこかで見かけた際は、よろしくお願いします。
*1:その内 bootie-docs にしようと思ってたけど、結局まだ出来てない。
Bash で pathctl という PATH 操作ツールと bb という簡易ベンチマークツールを書いた
小さな Bash のスクリプトを2つ書いたという小ネタです。
使い方
1. pathctl
環境変数に対する push
, pop
, shift
, unshift
操作を提供します。
#!bash source pathctl.shrc pathctl_push /path/to/your-bin # 末尾に追加 pathctl_unshift /path/to/your-bin # 先頭に追加 pathctl_pop # 末尾から除く pathctl_shift # 先頭から除く
2. bb
簡易ベンチマーク。
time コマンドを付けて引数で与えられたコマンドを一定回数実行して結果を出力するだけ。
## 例 $ bb.bash true "test -f bb.bash && echo true" "cat README.md" Exec 'true' 1000 times ... real 0m0.037s user 0m0.016s sys 0m0.019s Exec 'test -f bb.bash && echo true' 1000 times ... real 0m0.044s user 0m0.023s sys 0m0.019s Exec 'cat README.md' 1000 times ... real 0m1.972s user 0m0.820s sys 0m1.111s
source bb.bash
すると bb
という関数が読み込まれるので、この関数を使っても同じことができます。
回数を変えたいときは loop=$N bb ...
で($N
は数字)。
pathctl の高速化について
pathctl
を作ったきっかけは Qiita に書いたこちらの記事の状況でした。
これを最初に書いた直後に @sonots さんからコメント頂き、「RedHat 系 OS だったら pathmunge という関数があるよ」と知りました。
コードを見てみたところ、 pathctl
よりもシンプルで速そうだったので、この方式に修正してみることにしました。
実際どのくらい違うのか測ってみるついでに bb
を作った、という経緯です。
結果は こちらのイシュー に書いていますが、下にコピペします。
# pathmunge x 1000 Exec '. tmp/pathmunge.bash && pathmunge foo' 1000 times ... real 0m0.138s user 0m0.102s sys 0m0.031s # pathctl x 1000 高速化前 Exec '. pathctl.bash && pathctl_push foo' 1000 times ... real 0m5.024s user 0m2.249s sys 0m3.061s # pathctl x 1000 高速化後 Exec '. pathctl.bash && pathctl_push foo' 1000 times ... real 0m0.921s user 0m0.498s sys 0m0.311s
元々 pathmunge の1/40ぐらいのスループットだったのが、1/7ぐらいまでにはなった、というところです。
機会がありましたら、ご自由にご利用ください。
時系列DBって結局どれがいいんだっけ #TSDB
※4/6 その後調べた情報などを記事末尾に追記
前提となるニーズ
- サーバの負荷情報とか、アクセス状況のような KPI を取得・保存し、可視化(参照してグラフ化)したい。
- リアルタイム性が要求される。5分以上前のデータしか見れませんみたいなのはお呼びでない。
- 古いデータはそんなに精度は気にしないけど、ロングスパンで俯瞰して見れたら便利。
最近はビッグデータ環境の時系列データ解析もビジネスではけっこうニーズがありそうだけど、そっちはもう少し要求が多そう。
ここでは考えないことにする。
選択肢になりそうなもの
- 古きよき RRDtool
- Elasticsearch + Kibana
- Graphite + Grafana
- InfluxDB + Grafana 等
- Zabbix
他に、現実的には SaaS に任せるという手段もあるだろうけど、そう言うと話が終わってしまいそうなので、ここでは考えないことにする。
以下、順に所感を。
1. RRDtool
枯れてる。
一昔前のデファクトスタンダードの位置にあると思う。
Munin や Cacti などの監視ソフトウェアの多くで採用されているものでもある。
枯れているがゆえに目新しい話題はないが、自前でサーバメトリクス等を可視化する上では、まあまあ妥当な選択肢ではないだろうか。
各種開発言語のライブラリもあるし、GrowthForecast や CloudForecast のような RRDtool をラップしたツールもある。
2. Elasticsearch + Kibana
最近よく聞く組合せ。
Fluentd からデータを流して Elasticsearch + Kibana で可視化する、という例は枚挙に暇がない。
ログデータの可視化ではよく使われていそう。
やりようによってはその他のサーバメトリクスを載せることも可能だろう。
もともと検索エンジンであり、高機能なので、今回のニーズに対してはリッチ過ぎるという感もなくはない。
3. Graphite + Grafana
はてなや Y! で採用されている。
覚えている記事や発表の情報だと、「大規模だとつらそう」という印象。
4. InfluxDB + Grafana 等
一時期盛り上がったのだけど、最近あまり新しい話題を聞かない。
どうなったんだろう、という感じ。
オフィシャルページなど見たところ、開発は活発に続いている様子。
v0.9 でバックエンドの DB が LevelDB から BoltDB になったみたい。
※記事末尾に追記有り。
5. Zabbix
監視で取得したデータをかんたんにグラフ化できる機能があるようだ。
Zabbix は RRDtool ではないらしい。
全体的な補足
職場の Slack の #infra チャンネルでこの辺りのモヤモヤした疑問について、ふわっとつぶやいてみたところ、グラフツールを作ったりチューニングしていた人から、下のようなコメントを頂いた。
InfluxDB に期待したこともありましたが、なかなか難しいですね
描画部分も問題で、Kibana (or Grafana) は表示の時に頑張るので、グラフたくさん並べると遅いとかあったり、
ユースケースで選ぶ必要があると思っています。
その他
"timeseries db" や「時系列 DB」などで検索すると、他のプロダクトもちらほらヒットします。
OpenTSDB なんかは Hadoop と HBase をバックエンドにした大規模分析環境に向いてそうな時系列DBです。
雑なまとめ
決定版はいま無いのかなぁというところです。
「ユースケースによる」と言ってしまえばそれまでですが。
NewRelic 等の監視 SaaS や AWS の CloudWatch を使っているところもそれなりにあるでしょうし、「ツールが乱立している」とも言えるのかもしれませんね。
SaaS に頼らず自前でやるとして、正直、サーバメトリクス程度なら、そんなに大量になることは(たぶん、ふつう)ないので、どのツールでも工夫次第でなんとかできそうな気もしないでもないです。
使っている監視ソフトウェアが制約条件になるというケースもあるでしょう。
たとえば Zabbix を使っているなら、Zabbix で可視化するのが理に適っていると思います。
監視は監視でやっているけど、別途メトリクスも取りたいような場合は、どれを使うか迷う状況がしばらく続くかもしれません。
求む、決定版。
参考
- ログ集計/時系列DB/可視化ツールの調査結果 ... RRDtool は登場しませんが、それ以外についてはざっとまとまってる感じ。
- Graphs
- Prometheus - Monitoring system & time series database ... 記事を書いてる途中にたまたま見つけました。Go製のプロダクトで、単に時系列DBだけでなく、監視システムも含んでいるようです。GitHubでスター4000以上。
4/6 追記
その後調べたりして得た情報を追記しておきます。
RRDtool 2.x
RRDtool の作者 Tobias Oetiker が、次の15年も陳腐化しないことを見据えて RRDtool のリニューアルを計画している(していた?)ようです。
こちらは3年前の記事:
イシューで要求を募って、設計をドキュメントに書いている段階のようですが、イシューの最終更新は去年の7月なので、止まっていないか心配です。
InfluxDB のニュース
クラスタリング機能は将来的に Enterprise プランでのみの提供になるとのこと。
スタンドアローン版は OSS としての開発が継続されます。
その他
このランキングは参考になるなと思いました。/ DB-Engines Ranking - popularity ranking of time Series DBMS : https://t.co/Ot8lhosjl1 #TSDB
— きいあむ → @progrhyme (@key_amb) 2016年4月6日
mod_rrd_graph ってあるんだ。rrdgraphコマンドをNginx経由で叩けるようになる。これで事実上なんでもできるのかな。 #TSDB / “RRD Graph | NGINX” https://t.co/zwKiecaucy
— きいあむ → @progrhyme (@key_amb) 2016年4月6日
Git のリポジトリを1コマンドで統合できるシェルスクリプトを書いた
気づいたら GitHub にリポジトリが40個以上ありました。
古いものは作りかけだったり、実験して後に放置したものなどがいろいろありました。*1
そのままでも特に困ることはなく、これまで気にすることはなかったのですが、最近ときどき邪魔だなと思うことがあったので、少し整理することにしました。
本当にこれは要らないなと思うものはリポジトリを削除したのですが、一応取っておこうかなと思うものもあったので、リポジトリを統合する方法はないかなと検索してみたところ、下の記事を見つけました。
何度かこの通りにやって上手く行ったのですが、まだいくつか統合したいリポジトリがあったので、1コマンドで統合作業ができるようなスクリプトを書いてみました。
こんな感じで叩きます。
# 親リポジトリのトップディレクトリで git-merge-repository <統合対象のリポジトリURL> [ディレクトリ(省略可)]
第2引数のディレクトリを省略した場合は、統合対象のリポジトリ名がそのままディレクトリ名になります。
処理の流れは次のような感じ:
- 統合対象のリポジトリを
git clone
- clone したディレクトリに
cd
して、git filter-branch
でコミット履歴を書き換え
... 全てサブディレクトリ下の変更になるように書き換える filter-branch
の終了コードが 0 だったら確認プロンプトを表示。Y なら次に進む。(N なら終了)git remote set-url
で remote origin を親リポジトリの remote origin に変更git pull --rebase && git push origin master
... ここまでで remote リポジトリでは統合完了cd ..
で親リポジトリのディレクトリに戻り、clone したディレクトリをrm -rf
してgit pull
する
=> 統合されたディレクトリが fetch & merge される
注意点が2つあります。
- Qiita の記事のコメントにもありますが、Mac の
sed
では\t
がタブとして変換できませんでした。ので、CMD_SED=gsed
とシェル変数(or 環境変数)を付けて実行すればsed
の代わりにgsed
を使うようにしました。 - Qiita の記事では全てのブランチの履歴を取得する方法も載っていますが、このスクリプトでは
HEAD
固定になっています。
実行しているコマンド等、改良の余地はあるかと思いますが、とりあえず自分はこれで困ってないので、このまま紹介しておきます。
また、参考として、実際に動作させた環境情報は、MacOSX El Captain, git v2.5.4 (Apple Git), bash 4.3.x (Homebrew) です。
ユースケースはそんなにないかなと思いますが、機会がありましたらどうぞご自由にご利用ください。
余談
削除と統合の結果、GitHub 上のリポジトリは34個に減りました。
*1:そういうのは BitBucket に置くといいよ、というような話も聞いたことはあります。