即フォーマットチェックにincronを使う


こちらはニフティグループアドベントカレンダーの24日目記事です。

はじめに

今回はディレクトリやファイルの変更を監視してそのイベントが発生したら指定したコマンドが実行できるincronを紹介します。
使うことになった背景、incronについて、簡単な実装サンプルを書きましたのでご参考ください。

背景

ファイル連携しているあるシステムの現状です。

  • 連携先
    • 連携するファイルの作成は専用ツールで作成できるが、稀に手動で作成する場合もある。
    • 作成したファイルのフォーマットチェックができるシステムを持っていない。
    • WinSCPを使って連携元のサーバ(linux)にファイルを手動でアップロードしている。
  • 連携元
    • アップロードされたファイルはバッチで定期的に取得し、フォーマットチェックを行ってから取り込んでいる。

問題点

  • フォーマットに問題があった場合、フォーマットチェックを行っている連携元がエラーの原因を把握してリカバリーを行う必要がある。→ 時間がかかる。
  • 連携先はファイルをアップロードする時にエラーにならないか不安になる。

実現したいこと

ということで linuxのサーバにファイルがアップロードされたら即検知し、フォーマットチェックができるようにしたい、またその結果をSlackに通知することで連携先がエラー内容に気づき、すぐファイルの修正ができるようにしたかったです。

incronについて

ファイルアップロードの検知に使ったのは incron というものです。
Linuxカーネル2.6.13以降で使えて他のOSでは使えません。
ディレクトリやファイルの作成・修正・日付変更などのイベントをトリガーにして指定したコマンドが実行できます。

incronの使い方

CentOS 7を基準にします。yumを使ってインストールできます。

incronのインストール

$ sudo yum install incron
// デーモンの実行
$ sudo systemctl start incrond

incronの設定

使い方はcronと似ています。

// incronの設定
$ sudo incrontab -e

// incronの反映
$ sudo incrontab -d

// incron設定の確認
$ sudo incrontab -l

以下の例は /home/test/test.txt に何らかの修正が入ったら /home/test/start.sh を実行するという設定です。

<監視したいディレクトリやファイル> <トリガー> <実行コマンド>
/home/test/test.txt IN_MODIFY sh /home/test/start.sh

incronのパラメータについて

トリガー
トリガーは複数つなげて使うことができます。

トリガー 説明
IN_ACCESS ファイルにアクセスされた(読み取り)
IN_ATTRIB Metadata changed (権限、タイムスタンプ、拡張子など)
IN_CLOSE_WRITE 書き込み可能ファイルが閉じられた
IN_CLOSE_NOWRITE 書き込み不可能ファイルが閉じられた
IN_CREATE 監視ディレクトリにファイル/ディレクトリが作成された
IN_DELETE 監視ディレクトリからファイル/ディレクトリが削除された
IN_DELETE_SELF 監視対象のファイル/ディレクトリ自体が削除された
IN_MODIFY ファイルが修正された
IN_MOVE_SELF 監視対象のファイル/ディレクトリ自体が移動された
IN_MOVED_FROM ファイルが監視対象ディレクトリから移動された
IN_MOVED_TO ファイルが監視対象ディレクトリに移動された
IN_OPEN ファイルが開かれた

実行コマンド
実行コマンドには以下のワイルドカードをつなげて使えます。

ワイルドカード 説明
$$ $ をプリント
$@ 監視しているパス
$# イベントに関連されたファイル名
$% イベントのフラグ (文字)
$& イベントのフラグ (数字)

使い方の例

説明だけでは分かりにくいので実際に使ってみます。
/home/test/の配下にファイルが IN_CREATE(作成)されたら ワイルドカードたちを標準出力・ログに書き込みします。

// 設定の確認
$ incrontab -l
/home/test/     IN_CREATE       echo "$$ $@ $# $% $&" > /home/log/test.log

// ファイルを作成してみる
$ touch /home/test/test.txt 

// このように書かれました。
$ cat /home/log/test.log
$ /home/test/ test.txt IN_CREATE 256

ワイルドカードの中ではパスとファイル名を取得できる $@ $# がよく使えるのではないかと思います。

簡単サンプル(シェル)

/home/test ディレクトリ配下に作成されたファイルの名前が正しいかをチェックして結果をSlackに送るスクリプトです。
ここでの正しいファイル名とはtest_今日の日付です。

incron
$ sudo incrontab -l
/home/test      IN_CREATE       sh /home/test/file_name_check.sh $@ $# > /home/log/test.log
file_name_check.sh
#!/bin/bash

file_dir=${1}
file_name=${2}
valid_file_name=test_$(date "+%Y%m%d")

CHANNEL="[チャンネル名]"
TITLE="ファイルフォーマットチェック"
SLACK_WEB_HOOK='SlackのIncoming Webhook'

# ファイル名をチェック
if [ $file_name != ${valid_file_name} ]; then
  message="ファイル名が正しくありません。"
  status="danger"
else
  message="フォーマットに問題ありませんでした。"
  status="good"
fi

# slackに送信するのデータ
payload="payload={
    \"channel\": \"${CHANNEL}\",
    \"attachments\": [{
    \"title\": \"${TITLE}\",
    \"text\": \"ファイル名: ${file_name} \n 検証結果詳細: \n ${message}\",
    \"color\": \"${status}\"
    }],
}"

# slack送信
curl -s -S -X POST --data-urlencode "${payload}" ${SLACK_WEB_HOOK}

トリガーでシェルスクリプト(file_name_check.sh)を実行するようにしていますが、もちろんPHPやPythonなど別の言語のファイルも呼び出せます

動作確認

ファイルを二つOKとNGパターンで作成してみます。

// 今日の日付のファイル名
$ touch /home/test/test_20201214
// 未来日のファイル名
$ touch /home/test/test_20201225

このようにSlack通知されました。

最後に

もちろんAWS S3やLambdaを使うなどもっといけてる方法もありますが、
既存の環境の中で解決させる必要があったのでincronを採用しました。
同じ状況下であれば、incronはトリガー実行コマンドの組み合わせで色んなことができると思いますので使ってみてください。

では Merry Christmas Eve!

参考サイト