consul-templateのイベント発火トリガーについて調査した

ざっくり説明すると[consul-template](https://github.com/hashicorp/consul-template)とは
consulの様々なイベントを検知して
「テンプレート更新」 ＞ 「任意のコマンド実行」
してくれるツールです。

今回実現したかったのは **consul-kvsの変更をトリガーにしてほげほげする** ことです。
最初はconsul-templateがどういう条件でイベント発火するのかよくわからなかったのですが、
ドキュメントをよく見たらその辺りの仕様が記載されていたのでメモしておきます。

<br>

## どういう条件でwatchしているのか？
何の事はない話で、基本的には
``読み込むテンプレート内で利用している値が変更されたかどうか``
を見ているようです。
素晴らしいですね。（※一部例外あり）

<br>

## 例: kvsのキーの値を監視する場合
以下のようなテンプレートで ``key`` を参照するだけでよいです。

```/tmp/in_watch_key.tmpl
update hogekey > {{ key "/hogekey" }}
```

<br>

こんな感じでconsul-templateを実行して…

```bash
consul-template   -consul xxx.xxx.xxx.xxx:8500 -template "/tmp/in_watch_key.tmpl:/tmp/out_watch_key.tmpl:cat /tmp/out_watch_key.tmpl"
```

<br>

kvsを変更すると、以下のように表示されます（きちんと値が変わった時だけ発火する）

```bash
# kvsへput
curl -XPUT -d 'blahblahblah' http://xxxxxxx:8500/v1/kv/hogekey

# consul-template側
...
update hogekey > blahblahblah
```

<br>

## APIリファレンス
ついでに、どのようなAPIが定義されているかも記載しておきます。
see also: https://github.com/hashicorp/consul-template#api-functions

### datacenters
カタログ内の全てのデータセンターを表示（イベント発火なし）。

```bash
{{datacenters}}
```

### file
agent側のローカルファイル変更（中身を見ている様子）を監視／発火。
ユースケースがいまいち思いつかない…
また、consul-template起動時にファイルが存在していないとエラーになります。

```bash
{{file "/path/to/local/file"}}
```

### key
kvsのkeyの値を監視／発火。

```bash
{{key "service/redis/maxconns"}}
```

```bash
# データセンター指定版
{{key "service/redis/maxconns@east-aws"}}
```

### ls
kvsの指定したprefixトップレベルの全てのキーバリューを監視／発火。

```bash
{{range ls "service/redis"}}
{{.Key}} {{.Value}}{{end}}
```
上記の場合、 **"service/redis/*"階層のキーバリューの変更** を監視します。


### nodes

カタログ内の全てのノードを監視／発火。

```bash
{{nodes}}
```

```bash
# データセンター指定版
{{nodes "@east-aws"}}
```


### service
指定されたサービスグループに対して監視／発火。

```bash
# webappサービスを表示
{{service "webapp"}}
```

```bash
# rangeでは []*Service 構造体を返す
{{range service "webapp@datacenter"}}
server {{.Name}} {{.Address}}:{{.Port}}{{end}}
```

```bash
# デフォルトではヘルシーなサービス情報のみ表示するが、ステータスを指定して表示も可能

# ステータス関係なくすべてのサービスを表示
{{service "webapp" "any"}}
# ステータス＝passing のサービスを表示
{{service "webapp" "passing"}}
# ステータス＝passing or warning or critical のサービスを表示
{{service "webapp" "passing, warning, critical"}}
```

### services
カタログ内のすべてのサービスを表示。（サービス変更時のイベント発火について未確認）

```bash
{{services}}
```

```bash
# データセンター指定版
{{services "@east-aws"}}
```

```bash
# rangeで取ると、サービスの構造体でデータ参照することが出来ます
# see. http://www.consul.io/docs/agent/services.html
{{range services}}
{{.Name}}
{{range .Tags}}
  {{.}}{{end}}
{{end}}
```

### tree

kvsの指定したprefix以下の全てのキーバリューを監視／発火。

```bash
{{range tree "service/redis"}}
{{.Key}} {{.Value}}{{end}}
```
上記の場合、 **"service/redis/*" 以下の階層のキーバリューの変更** を監視します。

<br>

## 補足： ls と tree の違い

ドキュメント読んでてもいまいちイメージがわからなかったので
実際に動かして試してみました。

ls と tree は、そのままUnixコマンドのイメージで考えるとわかりやすいと思います。
ls は **指定した階層のみ** 、 tree は **指定した階層以下すべて** を対象にします。

### Example: ls
以下はすべて "service/redis" を指定している時の挙動です。

```bash
# NG： 指定したキーそのものを更新しても発火しません
curl -XPUT -d 'data' http://localhost:8500/v1/kv/service/redis

# OK: 配下のキーが増えた時
curl -XPUT -d 'xxx.xxx.xxx.xxx' http://localhost:8500/v1/kv/service/redis/node1
# OK: 配下のキーの値を更新した時
curl -XPUT -d 'yyy.yyy.yyy.yyy' http://localhost:8500/v1/kv/service/redis/node1

# NG: 階層を超えて増やしても発火しません
curl -XPUT -d 'aaa.aaa.aaa.aaa' http://localhost:8500/v1/kv/service/redis/node0/master
# NG: 深い階層のキーの値を更新しても発火しません
curl -XPUT -d 'bbb.bbb.bbb.bbb' http://localhost:8500/v1/kv/service/redis/node0/master
```

### Example: tree
以下はすべて "service/redis" を指定している時の挙動です。

```bash
# NG： 指定したキーそのものを更新しても発火しません
curl -XPUT -d 'data' http://localhost:8500/v1/kv/service/redis

# OK: 配下のキーが増えた時
curl -XPUT -d 'xxx.xxx.xxx.xxx' http://localhost:8500/v1/kv/service/redis/node1
# OK: 配下のキーの値を更新した時
curl -XPUT -d 'yyy.yyy.yyy.yyy' http://localhost:8500/v1/kv/service/redis/node1

# OK: 階層を超えて増えた時
curl -XPUT -d 'aaa.aaa.aaa.aaa' http://localhost:8500/v1/kv/service/redis/node0/master
# OK: 深い階層のキーの値を更新した時
curl -XPUT -d 'bbb.bbb.bbb.bbb' http://localhost:8500/v1/kv/service/redis/node0/master
```

## まとめ
consul-template、便利すぎてヤバい