あけましておめでとうございます。正月三が日は美味いメシを食ったり好きなときにぐーすか寝たりと悠々自適な生活をしていた一方で、サーバーのSSDが故障するというトラブルが発生しました。
うちのサーバーはLVMでソフトウェアRAIDを組んでいるので1つ壊れても運用に問題はなかったのですが、SYSLOGを見てみると実は1ヶ月前からディスクが壊れていたことが判明。これではさすがに気づくのが遅すぎるので、ディスクに異常が見つかったときにわかりやすく通知してくれる仕組みが欲しいところです。
ディスクの状態を確認するときは smartmontools
パッケージに入っている smartctl
コマンドを使用していたので、最初は smartctl
を cron
で定期実行させて異常があったら通知する、というような仕組みを作ってみました。ただ smartmontools
についてよく調べてみると、どうやらデフォルトで smartd
というデーモンがディスクを監視しており、異常をメールで通知してくれるようです。
せっかくなのでこの機能を使いたいところですが、ローカルのメールでは気づきにくいし、かと言ってわざわざメールサーバーを用意するのも手間なので、手軽にWebhookを使ってDiscordなどに通知させたいところ。そう思いながら smartd
の設定ファイルのマニュアル (smartd.conf(5)
) を見ていると、メールを送信する代わりに任意の実行ファイルを指定して実行させることができるとわかりました。
exec PATH - run the executable PATH instead of the default mail command, when smartd needs to send
email. PATH must point to an executable binary file or script.
さらに /usr/share/doc/smartmontools/examples/
にその実行ファイルとして使えるサンプルのスクリプトが置いてあり、 SMARTD_SUBJECT
や SMARTD_FULLMESSAGE
などの変数を通して smartd
から異常に関する情報を受け取れるようです。ちなみにこれらの変数の一覧は smartd.conf(5)
に書いてあります。
これらの情報をもとに curl
を使ってDiscordにWebhookでメッセージを送るスクリプトを書いてみました。
#!/bin/bash
set -eu
if ! command -v curl > /dev/null 2>&1; then
echo "Error: curl is not installed." >&2
exit 127
fi
function escape() {
echo "${1}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g'
}
DATA=$(cat << EOF
{
"username": "smartd",
"embeds": [
{
"title": "$(escape "${SMARTD_SUBJECT}")",
"color": 16711680,
"description": "$(escape "${SMARTD_FULLMESSAGE}")",
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")"
}
]
}
EOF
)
URL="MY_DISCORD_WEBHOOK_URL"
curl -H "Content-Type: application/json" -X POST -d "${DATA}" "${URL}"
SMARTD_SUBJECT
や SMARTD_FULLMESSAGE
にはどんな文字列が入るかわからないので、JSONに埋め込んでもエラーが起きないようにダブルクォーテーションや改行コードをエスケープする必要があります。本当は jq
のようなJSON用の処理系を使ったほうが安全なのかもしれませんが、依存するソフトウェアを減らしたかったので今回は sed
で置換することにしました。
このスクリプトを /usr/local/bin/
など適当な場所に置き、 /etc/smartd.conf
で下記のように指定します。
DEVICESCAN -d removable -n standby -m <nomailer> -M exec /usr/local/bin/smartd-discord-notifier
DEVICESCAN
を使うことで全てのデバイスをスキャンする対象にします。また、 -m <nomailer>
を指定することで -M exec
で指定した実行ファイルに対して、本来メールプログラムで使うための標準入力とコマンドライン引数を与えずに実行させます。
そしてテストのときだけ -M test
を追加で指定して smartd
を再起動。起動時にDiscordにテストメッセージが送信されているのが確認できました。
Discord廃人の私は、これでいつでもディスクの異常に気づくことができそうです。
環境
- Debian GNU/Linux 11 (bullseye)
- smartmontools release 7.2