Skip to content

Instantly share code, notes, and snippets.

@sasrai
Last active March 25, 2017 20:41
Show Gist options
  • Save sasrai/96a9b55f34b5fa233d665aeb107ab56a to your computer and use it in GitHub Desktop.
Save sasrai/96a9b55f34b5fa233d665aeb107ab56a to your computer and use it in GitHub Desktop.
SSDの世代バックアップをHDDに自動で取るやつ
#!/bin/bash
###########################################################
# Config
###########################################################
SEND_LOG_EMAIL=foobar@example.com
SENDER_EMAIL=report@example.com
TARGET=/hoge
BACKUP_DIR=/backups/hoge
BACKUP_WEEKLY_NUM=3
TIME_FORMAT="+%Y-%m-%d"
NEWBACKUP=$(date ${TIME_FORMAT})
NEWBACKUP_DIR=${BACKUP_DIR}/${NEWBACKUP}
# 火曜日がフルバックアップ日
LATEST_FULLBAKCUP=$(date ${TIME_FORMAT} -d "$(date '+%Y/%m/%d' -d 'tuesday') 1 week ago")
OLDEST_FULLBAKCUP=$(date ${TIME_FORMAT} -d "$(date '+%Y/%m/%d' -d 'tuesday') $((${BACKUP_WEEKLY_NUM} + 1)) week ago")
RSYNC_OPT="-av --delete"
###########################################################
# 関数
###########################################################
# http://wordpress.ideacompo.com/?p=4936
function date_diff() {
# 開始日の1900/1/1からの秒数を求める
START=$(date -d "$1" +%s)
# 終了日の1900/1/1からの秒数を求める
FINISH=$(date -d "$2" +%s)
# 終了日 - 開始日 の差分秒を求める
DIFF=$(($FINISH - $START))
# 秒分時で割ることで日数が求められる(小数点切り捨て)
DAYS=$(($DIFF / 60 / 60 / 24))
# 結果表示
echo $DAYS
}
function send_error_mail() {
cat <<- _EOT_ | sendmail -t
Delivered-To: ${SEND_LOG_EMAIL}
Return-Path: <${SENDER_EMAIL}>
To: ${SEND_LOG_EMAIL}
From: Rsync Backup <${SENDER_EMAIL}>
Subject: Backup ERROR.
Date: ${BACKUP_DATE}
Unknown error!!
_EOT_
}
###########################################################
# 実処理
###########################################################
# PATHにsbin追加(cron上でのsendmailとsmartctl用)
PATH=/usr/local/sbin:/usr/sbin:$PATH
# フルバックアップ日はここが一致
if [ ${NEWBACKUP} != ${LATEST_FULLBAKCUP} ]; then
# 前日からの差分を作らせる
YESTERDAY_BAKCUP=$(date ${TIME_FORMAT} -d '1 day ago')
if [ -d ${BACKUP_DIR}/${YESTERDAY_BAKCUP} ]; then
RSYNC_OPT="${RSYNC_OPT} --link-dest=../${YESTERDAY_BAKCUP}"
fi
fi
BACKUP_DATE=$(date -R)
SECONDS=0
RSYNC_LOG=$(rsync ${RSYNC_OPT} "${TARGET}"/* "${NEWBACKUP_DIR}")
if [ ! $? ]; then
send_error_mail
exit
fi
# 古いバックアップを削除
find ${BACKUP_DIR} -mindepth 1 -maxdepth 1 -type d | while read DIR; do
if [ 0 -gt $(date_diff ${OLDEST_FULLBAKCUP} $(basename ${DIR})) ]; then
echo ${DIR} is old...
if [[ $(basename ${DIR}) =~ ^20[0-9]{2}-[0-1][0-9]-[0-3][0-9]$ ]]; then
rm -rvf ${DIR}
fi
fi
done
# バックアップにかかった時間を保存
COPYTIME=${SECONDS}
# rsyncのログからサブディレクトリの一覧と内部のコピー数を取得
declare -A SUBDIRS
TMP_TARGET=${TARGET#*/}
RSYNC_LOG_FOOTER=$(tail -2 <<- _EOT_
${RSYNC_LOG}
_EOT_
)
RSYNC_LOG_HEADER_SKIP_LINES=2
if [ ! -d ${NEWBACKUP_DIR} ]; then
RSYNC_LOG_HEADER_SKIP_LINES=$((${RSYNC_LOG_HEADER_SKIP_LINES} + 1))
fi
RSYNC_FILE_LOG=$(tail -n +${RSYNC_LOG_HEADER_SKIP_LINES} <<- _EOT_ | head -n -2
${RSYNC_LOG}
_EOT_
)
IFS_ORIG="$IFS"
IFS=$'\n';
for LOG in ${RSYNC_FILE_LOG}; do
# 空行はファイルリストの最後(のはず)
if [ -z ${LOG} ]; then
break
fi
if [ -d ${NEWBACKUP_DIR}/${LOG%%/*} ]; then
SUBDIR=${LOG%%/*}
if [ ! -z ${SUBDIR} ]; then
SUBDIRS[${SUBDIR}]=$(( ${SUBDIRS[${SUBDIR}]:=0} + 1 ))
fi
fi
done
IFS="$IFS_ORIG"
# サブディレクトリ毎のコピーレポート作成
DIRS_LOG=$(for KEY in ${!SUBDIRS[@]}; do
_SIZE=$(du -sk "${BACKUP_DIR}/${NEWBACKUP}/${KEY}" | awk '{print"%\047d",$1}')
echo ${KEY}: ${SUBDIRS[$KEY]} records. \(${SIZE} kb\)
unset _SIZE
done)
# レポートメール本文作成
cat << _EOT_ | sendmail -t
Delivered-To: ${SEND_LOG_EMAIL}
Return-Path: <${SENDER_EMAIL}>
To: ${SEND_LOG_EMAIL}
From: Rsync Backup <${SENDER_EMAIL}>
Subject: Backup report.
Date: ${BACKUP_DATE}
Rsync backup report.
Backup time is ${COPYTIME}sec.
${RSYNC_LOG_FOOTER}
==== ====
Backup dirs report.
${DIRS_LOG}
==== ====
Latest full backup: ${LATEST_FULLBAKCUP}
Backup nums: $(ls -1d ${BACKUP_DIR} | wc -l)
Use storage: $(du -s ${BACKUP_DIR} | cut -d ' ' -f 1 | awk '{printf"%\047d",$1}') bytes
Reallocate sector: $(smartctl -A $(df ${BACKUP_DIR} | cut -d ' ' -f 1 | tail -1) | grep Reallocated | awk '{print $10}')
==== ====
Storage status.
$(df -h ${LATEST_FULLBAKCUP} ${TARGET})
==== ====
Raw S.M.A.R.T. Report.
$(smartctl --scan | cut -d ' ' -f 1 | while read dev; do sudo smartctl -A $dev; echo ; echo; done)
_EOT_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment