Github Webhook を受けて任意のスクリプトを実行するツール
ghooks-cmd-runner という、
Github の Webhook を受けて任意のスクリプトを実行する Go 製のツールを書きました。
Installation
https://github.com/tkuchiki/ghooks-cmd-runner/releases にバイナリがあるので、ダウンロードして解答してください。
Usage
$ ./ghooks-cmd-runner --help usage: ghooks-cmd-runner --config=CONFIG [<flags>] Receives Github webhooks and runs commands Flags: --help Show context-sensitive help (also try --help-long and --help-man). -c, --config=CONFIG config file location -p, --port=18889 listen port --host="127.0.0.1" listen host -l, --logfile=LOGFILE log file location --pidfile=PIDFILE pid file location --version Show application version.
config ファイルが必要なので、以下の様な TOML ファイルを用意します。
# port = 18889 (default: 18889) # host = "0.0.0.0 (default: 127.0.0.1)" # secret = "your webhook secret" # logfile = "path to logfile (default: stdout)" # pidfile = "path to pidfile" [[hook]] event = "push" command = "/path/to/script" [[hook]] event = "pull_request" command = "/path/to/script"
[[hook]]
の event
と command
を必要な分記述して、スクリプトを用意すれば完了です。
ghooks-cmd-runner
がスクリプトを実行する際、GITHUB_WEBHOOK_PAYLOAD
という環境変数に payload の JSON テキストを base64 でエンコードした文字列を格納しますので、環境変数を読んで base64 でデコードすればお好きな言語で payload を受け取とることができます。
シェルスクリプトで書くと以下のようになると思います。
echo ${GITHUB_WEBHOOK_PAYLOAD} | base64 -d ...
daemonize の機能はないので各自で行ってください。
追記
〜 2016-05-18 17:00
以下のバージョンをリリースしています。
- v0.1.2
- コマンドの標準(エラー)出力を1行ずつログに書き出すように修正
- v0.1.3
- hook[].branch オプション追加
- イベント毎に、正規表現にマッチした branch のみでコマンドを実行可能に
- hook[].branch オプション追加
- v0.2.0
- イベント毎に、コマンドを直列実行するように修正
時刻文字列をいい感じに parse する Go の package
parsetime という時刻文字列をいい感じに parse する Go のライブラリを書きました。
Example
使用例です。
package main import ( "fmt" "github.com/tkuchiki/parsetime" "log" ) func main() { p, err := parsetime.NewParseTime() if err != nil { log.Fatal(err) } t, err2 := p.Parse("2016-01-02T03:04:05") if err2 != nil { log.Fatal(err) } // Local timezone: JST // 2016-01-02 03:04:05 +0900 JST fmt.Println(t) }
以下、NewParseTime
と Parse
の説明です。
NewParseTime
NewParseTime
は 0 ~ 2 の引数を指定可能です。
引数を指定しなければ local の *time.Location
をセットした状態の time.Time を返します。
第一引数には *time.Location
と Asia/Tokyo
や JST
のような文字列を指定できます。
Asia/Tokyo
のような文字列を指定した場合は、
time.LoadLocation
して *time.Location
をセットします。
JST
のような文字列を指定した場合は、
その文字列から offset を取得して time.FixedZone
を実行します。
第一、二引数に JST
のような文字列、offset を指定した場合も time.FixedZone
を実行します。
ParseTime
構造体には、SetLocation
というメソッドを用意しているので、あとから変更することも可能です。
Parse
Parse
に時刻文字列を指定すると、time.Time
と error
を返します。
Parse
は、time.Parse
ではなく、正規表現でキャプチャして time.Date
を使う実装になっています。
最初に実装した時は、time.Parse
の format を大量に用意しておいて、
parse できるまでループで回していたのですが、正規表現を使ったほうが柔軟に対応できそうだったので実装しなおしました。
15:04
のように、時、分だけ指定した場合、実行した年月日を設定した time.Time
を返すようになっています
(time.Parse
をループで回していたときはこれができていませんでした)。
対応している文字列は、ISO8601、RFC 3339、RFC822, RFC850, RFC1123 などです。
01/02/2006 15:04:05
や11:04 PM
、Jan 2, 2006 at 3:04am (MST)
のような形式にも対応しています。
parse 可能な時刻文字列の例は https://github.com/tkuchiki/parsetime#examples を参考にしてください。
php-build が libphp[57].so を上書きしないようになりました
php-build が libphp5.so を上書きしないようにするパッチ で、
php-build が libphp5.so を上書きしてしまう問題を紹介しました。
2015-12-11 に Remove hard-patch code for APXS handling #353 が merge され、
libphp5.so(PHP 7 は libphp7.so なので、以降 libphp?.so) が上書きされないようになりました。
@tkak さんに Avoid overwriting apache module installed into user's libexec dir #204 を送って頂いていたのですが、方針と合わなかったのかこれ自体は Merge されませんでした。
送っていただいた Pull Request 自体が Merge されなかったのは残念ですが、
@tkak さんのお力添えで問題が解決されるまでに至りました。
ありがとうございました!
使い方
with_apxs2
という関数が追加されましたので、definitions に追記します。
# https://github.com/php-build/php-build/blob/master/bin/php-build#L491-L501 function with_apxs2() { local apxs="$1" shift if [ -z "$apxs" ]; then apxs="$PHP_BUILD_APXS" fi PHP_BUILD_APXS="$apxs" configure_option "--with-apxs2" "$apxs" }
# https://github.com/php-build/php-build/blob/master/bin/php-build#L576-L580 # Use php-build prefix for the Apache libexec folder if [ -n "$PHP_BUILD_APXS" ]; then apxs_libexecdir=$($PHP_BUILD_APXS -q LIBEXECDIR) sed -i"" -e "s|'\$(INSTALL_ROOT)${apxs_libexecdir}'|${PREFIX}${apxs_libexecdir}|g" ${source_path}/Makefile fi
となっていますので、apxs に path が通っていれば with_apxs2
、
通っていなければ with_apxs2 /path/to/apxs
と書けば libphp?.so の install path が変わります。
php-build には default_configure_options という、
全バージョン共通の configure のオプションを記述するファイルがあります。
こちらに --with-apxs2 /path/to/apxs
を書いても、
libphp?.so の install path が変更されませんのでご注意ください。
また、definitions に configure_option "--with-apxs2" "/path/to/apxs"
と書いても同様です。
しかし、異なるバージョンの php を install するごとに definitions を編集するのは大変です。
全部に追記したい場合は、以下のコマンドを実行すれば追記されます。
$ find /path/to/definitions -type f -print | xargs -I{} sh -c "grep -qs with_apxs2 {} || perl -p -i -e 'print \"with_apxs2 /usr/bin/apxs\n\" if $. == 1' {}"
追記済みの場合は何もしないので安心してお使いいただけるはずです。
上記のコマンドは色々な環境でも動くようにしたものですので、
GNU sed のある環境でしか使わない場合は以下のコマンドでも同じことができます。
$ find /path/to/definitions -type f -print | xargs -I{} sh -c "grep -qs with_apxs2 {} || sed -i '1i\with_apxs2 \"/usr/bin/apxs\"' {}"
まとめ
php-build が libphp?.so を上書きしてしまう問題への対応方法を紹介しました。
default_configure_options に書いたら libphp?.so の install path が変わったら楽そうだなと思いましたが、default_configure_options は全バージョン共通で使える configure option しか書かないと考えると、そういう方針なのだろうということで納得できました
(--with-apxs2
オプションは、現状 php-build が扱っている全バージョンで使えるようですが......)。
patch を当てる方法だとアップデートへの追従が大変なので、公式がサポートしてくれて良かったです。
jq で JSON を LTSV に変換する
結論
[ {"foo": "bar1", "hoge": "piyo1"}, {"foo": "bar2", "hoge": "piyo2"}, {"foo": "bar3", "hoge": "piyo3"} ]
という json(test.json とする) があるときに、
$ cat test.json | jq -r '.[] | to_entries | map("\(.key):\(.value)") | join("\t")'
と実行すると、
foo:bar1 hoge:piyo1 foo:bar2 hoge:piyo2 foo:bar3 hoge:piyo3
と出力されます。
解説
分解して説明します。
to_entries
で key
, value
という key を持った hash の array に変換します。
$ cat test.json | jq -r '.[] | to_entries' [ { "key": "foo", "value": "bar1" }, { "key": "hoge", "value": "piyo1" } ] [ { "key": "foo", "value": "bar2" }, { "key": "hoge", "value": "piyo2" } ] [ { "key": "foo", "value": "bar3" }, { "key": "hoge", "value": "piyo3" } ]
map は配列に対して処理を行え、
"(\.KEY)"
で文字列変数展開ができるので、
map("\(.key):\(.value)")
として Label:Value
の形式に変換します。
$ cat test.json | jq -r '.[] | to_entries | map("\(.key):\(.value)")' [ "foo:bar1", "hoge:piyo1" ] [ "foo:bar2", "hoge:piyo2" ] [ "foo:bar3", "hoge:piyo3" ]
最後に、join("\t")
で array を Tab 区切りの文字列に変換して完了です。
謝辞
http://stackoverflow.com/a/25378171 をちょっといじっただけです。
とても助かりました。aioobe さん、ありがとうございます!
fluentd の out forward の secondary を S3 にして信頼性を向上する
オートスケールするサーバ(web、アプリ)に立てている fluentd(以下、sender) から、
ログ集約用の fluentd(以下、aggregator) にデータを送るとき、
aggregator がデータを受け付けられないと sender で buffer すると思います。
この状態でスケールイン(ディスクごとサーバを削除)すると、
buffer していてもデータをロストしてしまいます。
そこで、sendor から aggregator に送れない場合は Amazon S3 に送ることができたのなら、
信頼性を向上できるのではないかと考え実験しました。
検証環境
fluentd 0.12.22
fluent-plugin-s3 0.6.6
ruby 2.3.0
注意点
sender から aggregator にデータを送れない状況を再現するために、
server には fluentd を起動していないホストを指定します。
存在しないホストを指定すると fluentd の起動に失敗するので、存在するホストを指定してください。
file buffer
buffer したデータを比較するため、まず file buffer の実験を行います。
以下の様な設定ファイルで fluentd を起動します。
以下の様に fluent-cat
でデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
buffer は msgpack なようなので decode するスクリプトを用意しました。
decode すると以下の様になります。
$ ruby unpack.rb /path/to/forward.debug.test.xxx.log [1459155557, {"foo"=>"bar"}]
s3 buffer
次は S3 に buffer できるかの実験です。
以下の様な設定ファイルで fluentd を起動します。
実験のため、retry_limit
と max_retry_wait
を非常に短くしています。
起動できたら file buffer の時と同じようにデータを送ります。
$ echo '{"foo": "bar"}' | fluent-cat debug.test
S3 を見るとデータが保存されていました。
送れていることが確認できたのならば、file buffer のときと同じく復元できるか確認します。
$ aws s3 cp s3://path/to/buffer/forward_debug.test.gz . $ gunzip forward_debug.test.gz $ ruby unpack.rb /path/to/forward.debug.test [1459155737, {"foo"=>"bar"}]
復元できました。
タイムスタンプ以外は同じ結果になったので、
aggregator を復旧すれば buffer からデータを再送できると思います。
まとめ
out forward の secondary を S3 にすることができるか検証しました。
検証に使った設定ファイルのままでは使えないと思いますので調整する必要はあると思いますが、
buffer をロストしにくくできそうですね。
実際に使用する場合は、S3 の buffer からデータを送り直す手順を確認しておくと良いと思います。
primary と secondary の type が違うのは推奨していないようで、
type of secondary output should be same as primary output primary="Fluent::ForwardOutput" secondary="Fluent::S3Output"
のような warn が出力されます。
secondary を S3 にした場合は問題なさそうな挙動でしたが、
他の plugin ではどうなるかわかりませんのでご注意ください。
プロセスのメモリ使用量とCPU使用率などが取れる mackerel-plugin-linux-proc-stats をリリースしました
プロセスのメモリ使用量と CPU 使用率などのメトリクスが取れる、
mackerel-plugin-linux-proc-stats をリリースしました。
Installation
https://github.com/tkuchiki/mackerel-plugin-linux-proc-stats/releases
からバイナリをダウンロードして解凍してください。
Usage
$ ./mackerel-plugin-linux-proc-stats --help Usage of ./mackerel-plugin-linux-proc-stats: -follow-child-processes Follow child processes -metric-key-prefix string Metric key prefix -pid string PID -pidfile string PID file -tempfile string Temp file name -version Version
このプラグイン独自のオプションを説明すると、
pid
: PID を指定pidfile
: PIDファイルの pathfollow-child-processes
: 子プロセスまで集計するか
となっています。
follow-child-processes
について説明するために実行例を示します。
nginx の master と worker プロセスが各1つずつ起動しているとします。
その状態で master プロセスの情報だけ取得する場合は、以下のように実行します。
$ ./mackerel-plugin-linux-proc-stats -pidfile /var/run/nginx.pid nginx_process.cpu.usage 0.000000 1458808477 nginx_process.memory.vsize 107450368.000000 1458808477 nginx_process.memory.rss 3399680.000000 1458808477 nginx_process.num.running 0.000000 1458808477 nginx_process.num.processes 1.000000 1458808477 nginx_process.num.threads 1.000000 1458808477
master と worker プロセス両方の情報を合算して取得する場合は、以下のように実行します。
$ ./mackerel-plugin-linux-proc-stats -pidfile /var/run/nginx.pid -follow-child-processes nginx_process.num.running 0.000000 1458808496 nginx_process.num.processes 2.000000 1458808496 nginx_process.num.threads 2.000000 1458808496 nginx_process.cpu.usage 0.000095 1458808496 nginx_process.memory.vsize 215269376.000000 1458808496 nginx_process.memory.rss 7966720.000000 1458808496
子プロセスまでしか追わないので、孫プロセスは対象外です(実装するか検討中)。
メトリクスについて
このプラグインは、/proc/PID/stat
を parse しています。
num.running
: 3番目が R かどうかnum.processes
: 指定したプロセスのプロセス数(follow-child-processes
をつけた場合は子プロセス含む)num.threads
: 20番目の値cpu.usage
: 15, 16 , 17, 22番目の値 とプロセスの起動時間、uptime、getconf CLK_TCK
の値を使って計算memory.vsize
: 23番目の値memory.rss
: 24番目の値
num.running
については、実行時間が長い処理を行わない限りは R にならないので、0 の場合がほとんどです。
/proc/PID/stat
の例を載せておきます。
10440 (nginx) S 1 10440 10440 0 -1 4202816 71 0 0 0 0 0 0 0 20 0 1 0 364149088 107450368 830 18446744073709551615 1 1 0 0 0 0 0 1073746048 402745863 18446744073709551615 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0
IAM の Switch Role を捗らせる
AWS のクロスアカウントアクセスを利用すると、
IAM ユーザを AWS アカウントごとに作成しなくても良くなり管理が容易になるのですが、
Switch Role する アカウントが多いと、履歴が 5 件しかないのでアカウントとロールを再入力しなくてはならないことが増えてきます。
ロールを切り替えるユーザーアクセス権限の付与 を見ると、
とあります。
Alias は以下を例にすると Your_AWS_Account_ID
です(参考: AWS アカウント ID とその別名)。
https://signin.aws.amazon.com/switchrole?YourAccount=hogehoge&roleName=YourRole
にアクセスすると、
アカウントとロールが入力された状態でアクセスすることができます。
また、ロールの切り替え(AWS マネジメントコンソール) を見ると、
とあり、 displayName
を指定すると表示名も入力した状態にできます。
また、color=カラーコード
で色を指定することもできます。
指定できる色は左から順に、
- F2B0A9 (何も指定しなくてもこれになります)
- FBBF93
- FAD791
- B7CA9D
- 99BCE3
です(右端の黒は指定方法がわかりませんでした)。
color についてはドキュメントに書いていないようでしたので、
変更される可能性があります。
最後に、account, roleName, displayName, color を全部指定した場合の例を示します。
https://signin.aws.amazon.com/switchrole?account=YourAccount&roleName=YourRole&displayName=YourDisplayName&color=99BCE3
にアクセスすると、
すべて入力済みになります。
この URL をブックマークしておくと、各項目を入力しなおさなくても良くなるので便利です。
まとめ
Switch Role の URL の query string に、
- account = alias または account ID
- roleName = ロール名
- displayName = 表示名
- color = カラーコード
を指定すると、各項目を入力済みの状態にできるので便利です。