はじめに
※あくまで個人的備忘録です
サーバ構築の一部で、以下を目的としたスクリプト作成をすることになった。
①ログ管理サーバに対象サーバのログファイルを収集する
②収集したファイルを一定のタイミングで削除
スクリプトの仕様について
処理概要図
①
sshコマンド経由で対象サーバに対してlsコマンドを発行する
②
①の出力結果から対象ファイルのパス情報を取得する
③
②で取得したパス情報を使用し、対象サーバにscpコマンドを発行する
④
ログ管理サーバに用意した一時保管領域にscp転送したファイルを保管する
⑤
一時領域に保管したファイルと、既に格納領域に保管されているファイルの更新日を比較する
⑥
⑤の結果、一時領域に保管したファイルの更新が新しい場合、そのファイルを圧縮状態にした後格納領域に移動する
⑦
⑤、⑥の処理後に一時領域をフォーマット(不要ファイルの削除)を行う
必要なコマンド
sshコマンドを使い、対象サーバ上でファイル情報の取得(ls)を行い、必要な部分だけ加工して取得する。
sshコマンド
ssh -i SSH鍵ファイル ユーザ@サーバ "ls -ltr 検索対象のファイルパス | tail -1 "| awk '{print $NF}'
# ls -ltr > l:詳細情報,t:更新時間順に並べる,r:逆順で表示する
# tail -1 > 末尾のみを対象とする
# awk '{print $NF}' > 実行結果の最終カラム(NF)のみ取得する
sccpコマンドで対象ファイルの転送を行う。帯域制御を行うため通信を圧縮し、元ファイルのパーミッションを維持する。
scpコマンド
scp -i SSH鍵ファイル -Cp ユーザ@サーバ:対象ファイル 転送先ディレクトリ
# -C : 通信を圧縮
# -i : コピー元の更新時間とモードを維持
if分岐
if [ 条件式 ] ; then
処理1
else
処理2
fi
検証して見えた検討事項
①sshをwhileで繰り返し処理をしたところ、ループせずに正常終了してしまった
sshコマンド実行時に標準入力が切り替わり、ローカルホストからの標準入力を停止し、リモートホストからの標準入力を受け付ける仕様なので、whileではなくforを使用することで解消。
実際に作ってみた
ディレクトリ構成
logcollect.sh
#!/bin/bash
## 変数
LC_USER=logcollect
LC_SSH_KEY=/home/logcollect/.ssh/id_rsa
LC_LOGFILE_LIST=/tmp/logfile.lst
# 一時領域フォーマット
function tmp_format(){
rm -f ${LC_TMPDIR}/*
}
## main
# リストファイルを元に繰り返し処理実行
for line in `cat ${LC_LOGFILE_LIST}`
do
# 0.リストファイルから接続先,取得対象ファイル,格納先を取得,圧縮状態(1:非圧縮,0:圧縮)
LC_HOST=`echo ${line} | awk -F ',' '{print $1}'`
LC_PATH=`echo ${line} | awk -F ',' '{print $2}'`
LC_FILE=`echo ${line} | awk -F ',' '{print $3}'`
LC_DIR=`echo ${line} | awk -F ',' '{print $4}'`
LC_ZIP=`echo ${line} | awk -F ',' '{print $5}'`
# 一時領域の格納先
LC_TMPDIR=`echo /log/tmp/${LC_HOST}`
# 1.対象の絞り込み
SCP_FILE=`ssh -i ${LC_SSH_KEY} ${LC_USER}@${LC_HOST} "ls -ltr ${LC_PATH}/${LC_FILE}|tail -1 "| awk '{print $NF}'`
# 2.scp実行
scp -i ${LC_SSH_KEY} -Cp ${LC_USER}@${LC_HOST}:${SCP_FILE} ${LC_TMPDIR}
# 一時領域に保存するファイル情報取得
TMPFILE1=`echo ${SCP_FILE} | awk -F '/' '{print $NF}'`
# 格納先の最新ファイル情報取得
TMPFILE2=`ls -ltr ${LC_DIR}/${LC_HOST}/${LC_FILE}`
if [ "$?" -ne 0 ]
then
# 格納先に比較対象ファイルが存在しない場合
TMPFILE2=`echo 0`
else
TMPFILE2=`ls -ltr ${LC_DIR}/${LC_HOST}/${LC_FILE} | tail -1 | awk '{print $NF}'`
fi
# 3.タイムスタンプ比較
test ${LC_TMPDIR}/${TMPFILE1} -nt ${TMPFILE2}
if [ "$?" -eq 0 ]
then
# 一時領域のファイルが最新の場合
if [ "${LC_ZIP}" -eq 1 ]
then
# 非圧縮ファイルを圧縮
gzip ${LC_TMPDIR}/${TMPFILE1}
fi
# 対象ファイルを格納領域に移動
mv ${LC_TMPDIR}/${TMPFILE1}* ${LC_DIR}/${LC_HOST}
fi
# 4.一時領域の不要ファイルを削除
tmp_format
#rm -f ${LC_TMPDIR}/*
done
logfile.lst
test-server,/var/log,cron-*,/log/System,1
test-server,/var/log,spooler-*,/log/System,1
test-server,/var/log,secure-*,/log/System,1
test-server,/var/log,messages-*,/log/System,1
test-server,/var/log,maillog-*,/log/System,1
test-server,/var/log/httpd,access_log-*,/log/System,0
test-server,/var/log/httpd,error_log-*,/log/System,0
365format.sh
#!/bin/bash
## 変数
TARGET_DIR=/log/System
#更新から1年(365days)経過したファイルを検索して削除
find ${TARGET_DIR} -mtime +5 | xargs rm -f
おわりに
内部事情はさておき、久々に仕事らしい仕事ができて非常に楽しい時間だった。
ただ、エラーに対する処理を実装することができなかったことが悔やまれる。また、自宅検証で成功しただけなので、実環境では更に改良が必要になると考えている。(実機調査の時点で問題を確認しているので1つや2つで済まないと思われる。。。。)
ただ、引継ぎしてくれる先輩方はハイスペックな人なので瞬殺してくれるだろう。
定期削除は日付情報を見て削除するだけなので説明するまでもないと思ってまとめてません。
参考
整理中。。。
↧