玄箱HG(debian lenny) のデータをLinkstationを起動、マウントして、rsyncするバックアップ処理を作った

大まかな仕様は以下

  • 通常電源OFF状態の、同一ネットワーク内にあるLinkstationを 定時刻に wakeonlan にて起動
  • 起動した Linkstation をネットワーク経由にてマウント
  • サーバデータを全てrsyncしてバックアップ
  • 処理の開始、終了時、特定のメールアドレスへメール送信する

必要パッケージのインストール

sudo apt-get update
sudp apt-get upgrade
sudo apt-get install wakeonlan
sudo apt-get install rsync
# mysql はインストール済みとする
# python はインストール済みとする

メール送信処理

特定アドレスにGメール送信する処理 Gmail 送信処理本体 GmailApi.py と、それを使用する sendMail.pyで構成

まずは、Gmail送信処理から

新規作成 vim GmailApi.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import smtplib
from email.MIMEText import MIMEText
from email.Header import Header
from email.Utils import formatdate

class sendGmail:
    def __init__(self, encoding, subject, body, from_addr, to_addr, login_addr, passwd):
        self.date = formatdate()
        self.encoding = encoding
        self.subject = subject
        self.body = body.encode('utf-8')
        self.from_addr = from_addr
        self.to_addr = to_addr
        self.login_addr = login_addr
        self.passwd = passwd

    def sendMail(self):
        msg = MIMEText(self.body, 'html', self.encoding)
        msg['Subject'] = Header(self.subject, self.encoding)
        msg['From'] = self.from_addr
        msg['To'] = self.to_addr
        msg['Date'] = self.date

        s = smtplib.SMTP('smtp.gmail.com', 587)
        s.ehlo()
        s.starttls()
        s.ehlo()
        s.login(self.login_addr, self.passwd)
        s.sendmail(self.from_addr, self.to_addr, msg.as_string())
        s.close()

上記を使用し、Gmail送信する処理 引数は以下で

  1. 送信先アドレス
  2. タイトル
  3. メール本文

新規作成 vim sendMail.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from GmailApi import *

argvs = sys.argv
argc = len(argvs)

if (argc != 4):
    print 'start arg count is not 4.'
    sys.exit(1)

encoding = 'utf-8'
to_addr = argvs[1]
subject = argvs[2]
body = argvs[3]
from_addr = 'XXXXXXXX@gmail.com'  # 送信元Gmailのアドレスを指定
login_addr = 'XXXXXXXX@gmail.com' # 送信元Gmailのアドレスを指定
passwd = '********'               # 送信元Gmailのパスワードを指定

sg = sendGmail(encoding, subject, body, from_addr, to_addr, login_addr, passwd)
sg.sendMail()

マジックパケットによる、wakeonlan 起動処理

Macaddress, IPアドレス(ブロードキャスト)、送信間隔を指定して、Magicpacket を送信し続ける処理
終了はKillで 新規作成 vim magic.packet.sh

#!/bin/bash
BROADCAST=$1 # ブロードキャストIPアドレス
MAC_ADDR=$2  # Linkstaionの Macaddress
INTERVAL=$3  # 送信間隔

fncMagicPacket()
{
    /usr/bin/wakeonlan -i $1 $2 >/dev/null 2>&1
}

while true
do
    fncMagicPacket $BROADCAST $MAC_ADDR
    sleep $INTERVAL
done

バックアップ処理本体

以下仕様

  • 処理開始・終了時指定アドレスへGmail送信
  • 同一ネットワーク内 Linkstation を wakeonlan 起動
  • 起動した Linkstaion をネットワークマウント
  • mysql dump し dump ファイルをHDD保存
  • サーバデータ全てを対象に Linkstaion へ rsync バックアップ
  • 完全同期型(サーバから消去されたデータは バックアップ先からも削除)

新規作成 vim backupserver.sh

#!/bin/bash
################################################################################
#   SETTINGS
################################################################################
#=========================================
#   BASE SETTINGS
#=========================================
SHELL_FLNM=`basename $0`
DIR_BIN=/tmp/bin # このファイル含め全てのプログラムが配置されているディレクトリを指定
DIR_LOG=/tmp/log # ディレクトリ作成済みのこと
DATE_STR="`date '+%Y%m%d.%H%M%S'`"
FIL_LOG=${DIR_LOG}/${SHELL_FLNM}.${DATE_STR}.log

#=========================================
#   ERROR MAIL PACKET SETTINGS
#=========================================
SEND_MAIL=${DIR_BIN}/sendMail.py
SEND_MAIL_TO=xxxxxxx@xxxx.xxx # バックアップ処理結果送信先を指定
SEND_MAIL_SUBJECT="好きなメールタイトルを"
SEND_MAIL_BODY=""

#=========================================
#   MAGIC PACKET SETTINGS
#=========================================
MAGIC_PACCKET=$DIR_BIN/magic.packet.sh
IP_BROADCAST=192.168.24.255 # ブロードキャストアドレスを指定
MACADDR_BACKUP_SRV=XX:XX:XX:XX:XX:XX # 対象の Linkstaion Macaddress を指定
MPACKET_INTERVAL=60 # マジックパケット送信間隔
MAGIC_PACCKET_PID=""

#=========================================
#   MOUNT SETTINGS
#=========================================
MOUNT_POINT_BKUP_SRV=/media/ls-xhle74 # Linkstaion マウント先
MOUNT_AT_BKUP_SRV=//ls-xhle74/share # Linkstaion 共有ディレクトリ
MOUNT_USR_NAME=XXXXX # Linkstaion マウントユーザを指定
MOUNT_USR_PWD=******** # Linkstaion マウントユーザパスワードを指定
MOUNT_UID=1000 # マウントオプション UID
MOUNT_GID=1000 # マウントオプション GID
MOUNT_INTERVAL_INIT=70 # マジックパケット初回wait
MOUNT_INTERVAL=10 # wakeonlan 起動待ち時、sleep時間
MOUNT_RETRY_LIMIT=6 # マウントリトライ最大回数

#=========================================
#   MYSQL SETTINGS
#=========================================
MYSQLDUMP_USR=XXXX # mysql ログインユーザ
MYSQLDUMP_PWD=******* # mysql ログインユーザパスワード
MYSQLDUMP_HST=localhost # mysql ホスト名
MYSQLDUMP_DATABASE=XXXXXXXXX # バックアップ対象データベース名
DIR_MYSQLDUMP=/tmp/mysqldump # データダンプバックアップ先
MYSQLDUMP_BASENAME=${MYSQLDUMP_DATABASE}.dump

#=========================================
#   RSYNC SETTINGS
#=========================================
RSYNC_FROM=/tmp # バックアップ対象 ROOT ディレクトリ
RSYNC_TO=${MOUNT_POINT_BKUP_SRV}/bkup # バックアップ先(Linkstaion)ディレクトリ
################################################################################

fncHandleError()
{
    if [ $1 -ne 0 ]
    then
        fncEndProc $1
    fi
}
fncLog()
{
    echo "$*" >> $FIL_LOG
}
fncEchoLog()
{
    MSG=$*
    DSTR=`date '+%Y%m%d:%H:%M:%S'`
    OUTMSG="[$SHELL_FLNM] $DSTR $MSG"
    fncLog "$OUTMSG"
    echo "$OUTMSG"
}
fncIsDirectoryCheck() {

    if [ ! -d $1 ] ; then
        fncEchoLog "[$1] is not directory."
        fncEndProc 1
    fi
}
fncWaitEnter()
{
    fncEchoLog "when you quit this program, input 'n' and enter."
    read Wait
    if [ "$Wait" = "n" ]
    then
        fncEchoLog "######################################"
        fncEchoLog "            Quited program            "
        fncEchoLog "######################################"
        read Wait
        exit
    fi
}
fncStartProc()
{
    fncEchoLog "######################################"
    fncEchoLog "            Start program             "
    fncEchoLog "######################################"
    $SEND_MAIL $SEND_MAIL_TO "(PROCESS STARTED) $SEND_MAIL_SUBJECT" "server backup process is started."
}
fncEndProc()
{
    if [ $1 -ne 0 ]
    then
        fncEchoLog "######################################"
        fncEchoLog "          !! Exception !!             "
        fncEchoLog "######################################"
        $SEND_MAIL $SEND_MAIL_TO "( !!! EXCEPTION OCCURED !!! ) $SEND_MAIL_SUBJECT" "---< EXCEPTION OCCURED >--- $SEND_MAIL_BODY"
    else
        fncEchoLog "######################################"
        fncEchoLog "          mission completed.          "
        fncEchoLog "######################################"
        $SEND_MAIL $SEND_MAIL_TO "(MISSION COMPLETED) $SEND_MAIL_SUBJECT" "server backup process is completed."
    fi
    exit
}

fncExecInternal()
{
    CMD=$*
    fncEchoLog "###########################################"
    fncEchoLog "  exec command. [$CMD]"
    fncEchoLog "###########################################"
    $CMD >>$FIL_LOG 2>&1
    RC=$?
}

fncExec()
{
    fncExecInternal $*
    if [ $RC -ne 0 ] ; then
        fncEndProc $RC
    fi
}

fncExecAllowError()
{
    fncExecInternal $*
}

fncStartMagicPacket()
{
    SEND_MAIL_BODY="error at magic packet process."
    fncEchoLog "Start magic packet process."
    fncEchoLog "###########################################"
    fncEchoLog "  exec command. [$MAGIC_PACCKET $IP_BROADCAST $MACADDR_BACKUP_SRV $MPACKET_INTERVAL & >>$FIL_LOG 2>&1]"
    fncEchoLog "###########################################"
    $MAGIC_PACCKET $IP_BROADCAST $MACADDR_BACKUP_SRV $MPACKET_INTERVAL & >>$FIL_LOG 2>&1
    MAGIC_PACCKET_PID=$!
    fncEchoLog "magic packet process started. pid=$MAGIC_PACCKET_PID"
}

fncStopMagicPacket()
{
    SEND_MAIL_BODY="error at stop magic packet process."
    fncEchoLog "Stop magic packet process."
    fncExec kill -9 $MAGIC_PACCKET_PID
}

fncWaitMountBkSrv()
{
    SEND_MAIL_BODY="error at mount linkstation process."
    fncEchoLog "Mounting. LinkStation."
    FLG_MOUNTED=0
    TRYCOUNT=1
    while [ $TRYCOUNT -le $MOUNT_RETRY_LIMIT ]
    do
        fncEchoLog "###########################################"
        fncEchoLog "  exec command. [mount -vt cifs $MOUNT_AT_BKUP_SRV $MOUNT_POINT_BKUP_SRV -o username=$MOUNT_USR_NAME,password=*****,iocharset=utf8,uid=$MOUNT_UID,gid=$MOUNT_GID]"
        fncEchoLog "###########################################"
        mount -vt cifs $MOUNT_AT_BKUP_SRV $MOUNT_POINT_BKUP_SRV -o username=$MOUNT_USR_NAME,password=$MOUNT_USR_PWD,iocharset=utf8,uid=$MOUNT_UID,gid=$MOUNT_GID >>$FIL_LOG 2>&1
        MOUNTRC=$?
        if [ $MOUNTRC -ne 0 ] ; then
            fncEchoLog "(RC=$MOUNTRC) mount error. try count $TRYCOUNT."
        else
            fncEchoLog "mount ok. try count $TRYCOUNT."
            FLG_MOUNTED=1
            break
        fi
        if [ $TRYCOUNT -eq 1 ] ; then
            fncEchoLog "Waiting for boot to complete the LinkStation. sleep ${MOUNT_INTERVAL_INIT} s"
            fncExec sleep $MOUNT_INTERVAL_INIT
        else
            fncExec sleep $MOUNT_INTERVAL
        fi
        TRYCOUNT=$(($TRYCOUNT+1))
    done
    if [ $FLG_MOUNTED -eq 0 ] ; then
        fncEchoLog "we could not mounted $MOUNT_AT_BKUP_SRV. we retry $MOUNT_RETRY_LIMIT count. last return cord is $MOUNTRC. we give up."
        fncEndProc $MOUNTRC
    fi
}

fncUnMountBkSrv()
{
    SEND_MAIL_BODY="error at umount linkstation process."
    fncExec umount $MOUNT_POINT_BKUP_SRV
}

fncBackupArchiveDatabase()
{
    SEND_MAIL_BODY="error at backup and archice database process."
    cd $DIR_MYSQLDUMP
    MYSQLDUMP_DUMPSQL=${MYSQLDUMP_BASENAME}.${DATE_STR}.sql
    MYSQLDUMP_DUMPTARGZ=${MYSQLDUMP_DUMPSQL}.tar.gz

    fncEchoLog "###########################################"
    fncEchoLog "  exec command. [mysqldump -u $MYSQLDUMP_USR -h $MYSQLDUMP_HST $MYSQLDUMP_DATABASE -p***** > $MYSQLDUMP_DUMPSQL]"
    fncEchoLog "###########################################"
    mysqldump -u $MYSQLDUMP_USR -h $MYSQLDUMP_HST $MYSQLDUMP_DATABASE -p$MYSQLDUMP_PWD > $MYSQLDUMP_DUMPSQL
    RC=$?
    if [ $RC -ne 0 ] ; then
        fncEndProc $RC
    fi
    fncExec tar cvfpz $MYSQLDUMP_DUMPTARGZ $MYSQLDUMP_DUMPSQL
    fncExec rm -fv $MYSQLDUMP_DUMPSQL
    # todo old data remove?
}

fncBackupAllData()
{
    SEND_MAIL_BODY="error at rsync process."
    fncEchoLog "Start sync to backup data. from=[$RSYNC_FROM] to=[$RSYNC_TO]"
    fncExec rsync -vrual --delete $RSYNC_FROM $RSYNC_TO
}

fncMain()
{
    fncStartProc

    # start magic packet.
    fncStartMagicPacket

    # wait and mount linkstation
    fncWaitMountBkSrv

    # buckup and archive database
    fncBackupArchiveDatabase

    # backup all data
    fncBackupAllData

    # unmount linkstation
    fncUnMountBkSrv

    # stop magic packet.
    fncStopMagicPacket

    fncEndProc $RC
}

fncMain