Pacemaker の CIB を KVS っぽく使う

Pacemaker/Corosync でクラスタを組んでいるとき、例えばアクティブ機でスクリプトを実行して、その結果をどこかに保存して、アクティブ機が死んでフェイルオーバーしたときにその結果を引き継いで使いたいことがあります。

例えば DRBD でディスクのミラーリングをしたり、あるいは別で構築した MySQL とかの RDBMS に保存したり、いやいや Redis とかの KVS のが良いだろう、とかの案はあると思いますが、せいぜい 30 秒に 1 回ぐらいの頻度で数バイトを読み書きする程度であればそれだけのためにわざわざ DRBD だの何だのは過剰な気がします。

そもそも Pacemaker/Corosync によってクラスタメンバ同士で情報のやり取りは行われているわけなので、そこをちょっとしたデータを保存するための KVS として使ってみました。

## attrd_updater

pingd という ocf で ping 結果がノードの属性として保存されているので、同じ方法で任意のデータを保存できないか試してみました。

pingd のスクリプトを見た感じ `attrd_updater` というコマンドで ping 結果を保存していました。

このコマンドは CIB の `/cib/status/node_state/` の中に値を保存するため、ノードごとの属性値として保存されます。`-N` でノード名を指定できますが省略すれば自ノードとなります。

属性の名前は `-n` で指定します。値は `-v` または `-U` で指定します（man だと `-U` だけど pingd は `-v` を使ってた）。

```sh
attrd_updater -n oreore -v 999
attrd_updater -n oreore -U 999
```

値の取得は `-Q` です。

```sh
attrd_updater -n oreore -Q
```

次のように結果が返ります。

```
name="oreore" host="pm01" value="999"
```

値が格納されていないノードで実行すると下記のように空文字列になります。

```
name="oreore" host="pm02" value=""
```

どのノードでも値が保存されていない属性名を指定するとエラーになります。

```
Could not query value of areare: attribute does not exist
```

`-A` を追加で指定するとすべてのノードの値が返されます。

```sh
sudo attrd_updater -n oreore -Q -A
```

次のように複数行の結果が返ります。値が格納されていないノードの結果は返らないようです。

```
name="oreore" host="pm01" value="999"
name="oreore" host="pm03" value="777"
```

やってみたらできたんですけど、存在しないノードの値も保存できました。

```sh
sudo attrd_updater -N pm99 -n oreore -v 000
sudo attrd_updater -n oreore -Q -A
```

```
name="oreore" host="pm01" value="999"
name="oreore" host="pm03" value="777"
name="oreore" host="pm99" value="000"
```

削除は `-D` です。

```sh
sudo attrd_updater -n oreore -D
```

属性を最初に保存するときに `-p` を付けると CIB に保存されなくなるらしいです。

```sh
sudo attrd_updater -n areare -v 999 -p
```

Pacemaker の再起動時にノードの属性値が復元されるかどうかの違いがあるのかと思ったんですけど・・`-p` があっても無くても再起動で属性値は消えました。

ノードの再起動で属性値を維持するためには `-l` でライフライムを指定する必要があるのかな？

```sh
sudo attrd_updater -n oreore -v 999 -l forever
```

と、思ったんですけどやっぱり Pacemaker を再起動すると消えました。`attrd_updater` だとどうやっても Pacemaker の再起動時にそのノードの属性値は消えるようです。

## crm_attribute

`crm_attribute` ならノードごとの属性値以外のものも保存できます。

`-t` で属性の種類を指定、`-n` で属性名の指定、`-v` で値の指定です。属性の種類はデフォルトは `crm_config` ですが、`rsc_defaults` `op_defaults` `tickets` などが指定できます。

```sh
crm_attribute -t crm_config   -n oreore_crm_attr -v 999
crm_attribute -t rsc_defaults -n oreore_rsc_attr -v 999
crm_attribute -t op_defaults  -n oreore_op_attr  -v 999
crm_attribute -t tickets      -n oreore_tickets  -v 999
```

`tickets` が何なのかはよく判りませんが、その他の属性は `pcs property set` とか `sudo pcs resource defaults` とかで設定するものと同じものなので、KVS のように使うなら意味ある名前と被らないように注意する必要があります。

`-N` でノードを指定すると CIB の `/cib/configuration/nodes/node/` に保存されます。この値はノードの Pacemaker を再起動しても消えませんでした。

```sh
crm_attribute -N pm01 -n oreore_node_attr -v 999
```

`-t` で `status` を指定すると `attrd_updater` と同じ `/cib/status/node_state/` に保存されました。この値はノードの Pacemaker を再起動すると消えます。

```sh
crm_attribute -t status -N pm01 -n oreore_status_attr -v 999
```

ノードを指定するときは `-l` でライフタイムを指定できます。`-l forever` だと `/cib/configuration/nodes/node/` に保存されて、`-l reboot` だと `/cib/status/node_state/` に保存されます。

```sh
crm_attribute -N pm01 -l forever -n oreore_node_forever -v 999
crm_attribute -N pm01 -l reboot  -n oreore_node_reboot -v 999
```

つまり、下記の3つは同じ場所に保存されます。

```sh
attrd_updater -N pm01 -n oreore_node_status -v 999
crm_attribute -N pm01 -l reboot -n oreore_node_status -v 999
crm_attribute -N pm01 -t status -n oreore_node_status -v 999
```

あ、というかソース見てて気づいたんですけど `-l` と `-t` って同じですね・・なので次のようなものも通ります。

```sh
crm_attribute -l rsc_defaults -n oreore_life_rsc -v 999
crm_attribute -N pm01 -t reboot -n oreore_type_reboot -v 999
```

`-z` を指定すると `/cib/nodes/node/utilization/` に保存されました。たぶん本来は CPU とかメモリの使用量を元にリソースの配置を決定するために使う場所なのだと思います。

```sh
crm_attribute -z -n oreore_utilization -v 999
```

属性値の取得は `-G` です。

```sh
crm_attribute -t crm_config -n oreore_crm_attr -G
```

次のように結果が返ります。

```
scope=crm_config name=oreore_crm_attr value=999
```

`-q` を追加で指定すると値だけ取得できます。

```sh
crm_attribute -t crm_config -n oreore_crm_attr -G -q # 999
```

削除は `-D` です。

```sh
crm_attribute -t crm_config -n oreore_crm_attr -D
```

mysql や galera の ocf を見るに、ノードごとの値のために `-l reboot` とか `-l reboot` が、クラスタ全体の値のために `-t crm_config` が使用されていました。

## crm_resource

リソースに紐付く属性値を保存するために `crm_resource` が使えそうです。

`-r` でリソース名を指定します。保存するときは属性名を `-p` で指定して `-v` で属性値を指定します。

```sh
crm_resource -r dummy -p oreore_resource -v 789
```

取得は `-g` で属性名を指定します。

```sh
crm_resource -r dummy -g oreore_resource # 789
```

削除は `-d` です。

```sh
crm_resource -r dummy -d oreore_resource
```

`-m` を指定するとリソースのメタデータを操作できます。

```sh
crm_resource -r dummy -m -p oreore_resource_meta -v 789
```

`-z` を指定するとリソースの utilization の値を操作できます。たぶん本来はノードの utilization と同じような使い方なのだと思います。

```sh
crm_resource -r dummy -z -p oreore_resource_utilization -v 789
```

これらの属性はリソース作成時のパラメータやメタデータと同じものなので、意味あるものと被らないようにする必要があります。

```sh
crm_resource -r dummy -g state                   # /tmp/pm-dummy
crm_resource -r dummy -m -g migration-threshold  # 1
```

既存の ocf を見た感じ VirtualDomain という ocf が utilization を更新するためだけに使っていました。

## まとめ

まとめると、下記のように使い分けるのが良いのかなって思います。

```sh
# クラスタ全体の値
crm_attribute -t crm_config -n "$attr_name" -v "$attr_value"
crm_attribute -t crm_config -n "$attr_name" -G -Q

# ノードごとの値でノードのリブートで消える
crm_attribute -N "$nodename" -l reboot -n "$attr_name" -v "$attr_value"
crm_attribute -N "$nodename" -l reboot -n "$attr_name" -G -Q

# ノードごとの値でノードがリブートしても消えない
crm_attribute -N "$nodename" -l forever -n "$attr_name" -v "$attr_value"
crm_attribute -N "$nodename" -l forever -n "$attr_name" -G -Q
```

`attrd_updater` は複数ノードの値を一度に取得できたりしますが、値だけの取得が面倒そうです。pingd のように書き込みだけ行って値の参照は Pacemaker の constraints でしか使わない、とかならありかもしれません。

`crm_resource` は特定のリソースに紐付く値を保存する目的なら最適だと思ったんですけど・・使っている ocf が無かったので手を出して良いのかどうか判りません。