#!/bin/bash

#运行该脚本前请确保主从服务器中已安装如下程序或服务,需备份服务器(master):ssh、rsync、inotify-tools;备份服务器(slave):ssh

#Synopsis:ssh-keygen+rsync+inotifywait组合,生成可从远程备份服务器slave server实时动态备份生产服务器master server数据的功能

#Function:本脚本需要本地服务器(master server)免密码登陆到备份服务器(slave server),因此需要主从服务器上均安装有ssh服务

#此版本用到rsync的ssh协议传输,所以需要用到ssh-keygen生成公私钥,该功能脚本在另一篇日志已贴出,该脚本有log日志记录功能

#为防止误操作,对于master server监视目录中delete或move from的文件或目录,将会在slave server上暂时保留,并未彻底删除

#Usage:在需要备份的服务器上运行本脚本:./inotifyRsync.sh 2>/var/log/inotify/rsyncstd_error.log &,可根据需要添加到

#/etc/rc.local,以实现开机自启

#Notes:使用本脚本要求master和slave服务器上的路径相同;运行脚本一定要当前进程执行,如果sh program执行,则有的事件无法捕捉到,

#导致同步失败

#Date:2016/11

#Author:Jian

#Version:v1.0


#Variable definition

inoDir="/var/log/inotify"

#slave server ip

rsServer="192.168.1.26"

#slave server username

rsUsr="root"

#master & slave server watched directory

srcDir="/rsbackup/rs"

#slave server directory(delete or moved_from the watched dir)

#该目录为从服务器上的备份目录,目的是为防止主服务器上误操作,从监视目录中删除文件后,从服务器会将相同

#文件先移出slave的监视目录,而移出的目标目录就是oldFiles

oldFiles="/oldFiles"

#判断slave server监视目录和备份目录是否存在,否则创建之

ssh -t -q -n "$rsUsr"@"$rsServer" "[ ! -d "$srcDir" ] && mkdir -p "$srcDir""

ssh -t -q -n "$rsUsr"@"$rsServer" "[ ! -d "$oldFiles" ] && mkdir -p "$oldFiles""

#判断master server日志目录是否存在,否则创建之

[ ! -d "$inoDir" ] && mkdir -p "$inoDir"

#master 开启inotifywait,监视指定目录

/usr/local/inotify-3.14/bin/inotifywait -mrq -e close_write,create,moved_to,moved_from,attrib,delete \

--format '%w*%f*%Xe' $srcDir | tee $inoDir/inotify_events.`date +%Y%m%d`.log \

| while read line 

do

 #inotifywait命令输出格式如:/rsbackup/rs/*backup*MOVED_FROMXISDIR

  inoPath=$(echo $line | awk -F"*" '{print $1}')    #inotifywait命令输出分段,eg:inoPath=/rsbackup/rs/

  inoFile=$(echo $line | awk -F"*" '{print $2}')    #eg:inoFile=backup

  inoAction=$(echo $line | awk -F"*" '{print $3}')  #eg:inoAction=MOVED_FROMXISDIR

  rsyncSuccess=$inoDir/rsync_success.`date +%Y%m%d`.log #rsync同步成功记录日志

  rsyncError=$inoDir/rsync_error.`date +%Y%m%d`.log     #rsync同步失败记录日志

  #下面对捕捉到的inotifywait输出的每一个Filename和Action分别处理

  #file or dir moved from start location

  if [ "$inoAction" = "MOVED_FROM" ] || [ "$inoAction" = "MOVED_FROMXISDIR" ] || [ "$inoAction" = "DELETE" ] || [ "$inoAction" = "DELETEXISDIR" ] 

  then

      ssh -t -q -n "$rsUsr"@"$rsServer" "[ -d "$inoPath$inoFile" ] || [ -f "$inoPath$inoFile" ] &&  mv $inoPath$inoFile "$oldFiles""

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : FILE OR DIR(moved from successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : FILE OR DIR(file or dir moved from failure) : $inoPath$inoFile" >> $rsyncError

      fi

    fi

  #file or dir moved from end location

  #new file create start location

  echo "$inoFile" | grep -Ev "\...*sw[a-z]x?$" > /dev/null #grep -Ev用于排除正在编辑的.swx/.swp/.swpx等临时文件

  if [ $? -eq 0 ];then  

    if [ "$inoAction" = "CLOSE_WRITEXCLOSE" ];then

      rsync -ahzc -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"  #rsync同步

      if [ $? -eq 0 ];then  #判断上面的rsync同步是否成功执行,否则生成传输错误日志

        echo "`date "+%Y%m%d%H%M%S"` : FILE(create or edit or cp -af successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : FILE(create or edit or cp -af failure) : $inoPath$inoFile" >> $rsyncError

      fi

    fi

  fi

  #new file create end location

  #file renamed or moved start location

    if [ "$inoAction" = "MOVED_TO" ] ;then

      rsync -ahzc -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : FILE(renamed or moved successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : FILE(renamed or moved failure) : $inoPath$inoFile" >> $rsyncError

      fi

    fi

    #file renamed or moved end location

    #dir create or cp -r start location

    if [ "$inoAction" = "CREATEXISDIR" ];then

      rsync -aruzc -d -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : DIR(create or cp -r successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : DIR(create or cp -r failure) : $inoPath$inoFile" >> $rsyncError

      fi

    fi

   #dir create or cp -r end location

   #dir renamed or moved to start location

    if [ "$inoAction" = "MOVED_TOXISDIR" ];then

      rsync -aruzc -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : DIR(renamed or moved to successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : DIR(renamed or moved to failure) : $inoPath$inoFile" >> $rsyncError

      fi

    fi

   #dir renamed or moved to end location

   #file attrib changed start location

   if [ "$inoAction" = "ATTRIB" ];then

     rsync -aruzc -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : FILE(attribute changed successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : FILE(attribute changed failure) : $inoPath$inoFile" >> $rsyncError

      fi

   fi

   #file attrib changed end location

   #dir attrib changed start location

   if [ "$inoAction" = "ATTRIBXISDIR" ] && [ -n "$inoFile" ];then

     rsync -auzc -d -e ssh "$inoPath$inoFile" "$rsUsr"@"$rsServer":"$inoPath"

      if [ $? -eq 0 ];then

        echo "`date "+%Y%m%d%H%M%S"` : DIR(attribute changed successfuly) : $inoPath$inoFile" >> $rsyncSuccess

      else

        echo "`date "+%Y%m%d%H%M%S"` : DIR(attribute changed failure) : $inoPath$inoFile" >> $rsyncError

      fi

   fi

   #dir attrib changed end location

done