Undefined Title

githubのwebhook用サーバをつくった

2014-07-31

githubのWebhook、皆さん使ってますか。Webhookを受け取るサーバって何使ってますか、sinatraですか?このエントリは社内でserfのデモ用に書いた、github webhook用のHTTPサーバhoko in golangについてのエントリです。

TL;DR

背景

みんなどうしてるんだろう、という疑問とともにさらなる要求も。

それserfでできるよ

もとあったRubyのコードをgolangで書き直したいなあと思って、最初はwebhookイベントに対応した名前のshellスクリプト呼び出すような簡易サーバ書いてたんだけど、ちょっと条件つけようとするとタグとかそういう仕組が欲しくなってきて、複雑になりそうなところで思いとどまること数時間。

そんなところに、ふとHashiCorpの神が降りてきた。
serfです、serfを使うのです、と。

    [github]
       |
       |  webhook
       |
       `---- POST ----> [hoko]  invoke serf query
                          A
                          |  joining cluster 
                          |
                        [serf agent]
                          |
                          |  exec by query
                          |
                           `----> [event-handler]

つまりイベントハンドラの登録、タグの指定方法のI/Fにserfを使って一般化しようという意図です。そこら辺を自分で作りこむとオレオレI/Fになってしまうので、できるだけありものを使いたかった、と。

webhookを受け取る部分は、認証とbodyのparse、serf queryの発行だけをやる、つまりserfのgithub webhook用HTTP interfaceってこと。

設定や実行方法

設定や実行方法はREADMEに詳しく書いた。ローカルでも動作確認はできるのでイベントハンドラのテストも簡単にできる。また実際イベントを受けてからの動作はserfのレイヤなのでhoko関係なく考えられる。

一応ここでも簡単に触れると、バイナリはここからダウンロード、そしてこんな設定ファイルをバイナリと同じディレクトリにserf.confとして置く。これはserfの設定ファイルそのまま。

{
  "tags": {
    "webhook": ".*"
  },
  "event_handlers": [
    "query:hoko=./handler/echo.sh"
  ]
}

あとはイベントハンドラにあたるコマンド./handler/echo.shを用意する。

$ ./hoko run -d &
==> Starting Serf agent...
==> Starting Serf agent RPC...
...
    2014/07/27 10:18:04 [INFO] agent: Received event: member-join

$ curl localhost:3000/serf/query/hoko -d '{}'
{
  "Acks": [
    "hostname"
  ],
  "Responses":
    "hostname": "\n------- ./handler/echo.sh\nSERF_EVENT: query\nSERF_QUERY_NAME: hoko\nSERF_SELF_NAME: hostname\nSERF_TAG_WEBHOOK: .*\npayload: \"event\":\"\",\"ref\":\"\",\"after\":\"\",\"before\":\"\"}\n\n\n"
  }
}

hokoを実行してcurlでリクエストを投げると、上記のようなレスポンスが返ってくる。Responsesのhostnameの値、これは./handler/echo.shの出力だ。hostnameは実際は実行したホスト名が入る。

ちょっとだけ気をつけないといけないのは、serfのpayloadは1024byteまでだから、webhookのPOSTのbodyはそのまますべてをイベントハンドラへは渡せないこと。今は適当にピックアップしたフィールドをpayloadとしています。ref,after,before、あとはx-github-eventヘッダのをeventとして。

今のところコードはimport含めて200行もないので何やってるかはすぐ見通せるはず。

締め

hokoはserfのquery起動のためのHTTPのインタフェースを提供するもので、今はx-github-event解釈とかbodyのJSON schemaはgithub用だよという感じ。

今後はクエリパラメータでタグを指定するとか、serf eventコマンドも発火できるようにするとかの改良を入れたい。

あと、一番めんどくさかったのは正直x-hub-signatureverifyでした。ぜんぜん一致しなくて泣きそうだった…。