Sunday, December 30, 2012

FreeBSD下用 shell script 建立ZFS snapshot 更新版

此次更新的目的是讓 ZFS 不使用 ls /PATH/.zfs/snapshot 目錄判斷快照數量(為了避開 Bad file descriptor 問題). 中間版本曾經使用 /usr/local/bin/snapshot list 進行, 但是速度較慢. 好在這個檔案是 shell script. 看了一下 op_list 函式的內容看到取得目前已有的快照方法, 也了解到這隻程式慢在還要查詢及計算使用空間等數據. 所以將查詢改用 zfs list -H -t snapshot -o name | grep "ZPOOL_NAME/ZVOL_NAME@". (ZPOOL_NAME/ZVOL_NAME 可以使用 zfs list -H -o name ${volpath} 查詢得到)



程式碼
#!/usr/local/bin/bash

PATH=$PATH

LOGFILE="/var/log/snapshotfs.log"
TODAY=`date +"%Y%m%d"`
UFSSSCMD="/usr/local/sbin/snapshot"
TMPFILE="/tmp/snapshotfs"
CHKPARA=0

if [ -n "$1" ]; then
 fstype="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 sstype="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 maxnum="$1"
 shift
else
 CHKPARA=1
fi


if [ -n "$1" ]; then
 volpath="$1"
 shift
else
 CHKPARA=1
fi

if [ $CHKPARA -eq 1 ]; then
 echo "Usage: $0 fstype sstype maxnum /filesystem|volume_path"
 echo "Example: $0 zfs [H|D|W|M|Q|Y] 7 /databackup/backup"
 exit 1
else
 touch $LOGFILE
 echo `date +"%Y/%m/%d %H:%M:%S"` >> $LOGFILE
 echo "$0 $fstype $sstype $maxnum $volpath" >> $LOGFILE
 echo "Check parameters for taking a snapshot of $volpath($fstype)." >> $LOGFILE
fi

if [ -d $volpath ]; then
 if [ $fstype = 'zfs' ]; then
  if [ -d $volpath/.zfs ]; then
   echo "Check path : OK" >> $LOGFILE
  else
   echo "Check path : Failed, snapshot folder does not exist." >> $LOGFILE
   exit 1
  fi
 elif [ $fstype = 'ufs' ]; then
  if [ -d $volpath/.snap ]; then
   echo "Check path : OK" >> $LOGFILE
  else
   echo "Check path : Failed, snapshot folder does not exist." >> $LOGFILE
   exit 1
  fi
 else
  echo "Unsupported file system $fstype" >> $LOGFILE
  exit 1
 fi
else
 echo "Check path : Failed, filesystem|volume_path does not exist." >> $LOGFILE
 exit 1
fi

if [ $maxnum -gt 0 ]; then
 echo "Check maxnum : OK" >> $LOGFILE
else
 echo "Check maxnum : Failed, must input positive integer." >> $LOGFILE
        exit 1
fi

TMPFILE="${TMPFILE}-"`date +"%s"`"-${fstype}-"`md5 ${volpath} | awk '{print $4}'`
touch ${TMPFILE}

if [ $fstype = 'zfs' ]; then
 echo "ZFS" >> $LOGFILE
 ZFSDSET=`zfs list -H -o name ${volpath}`
 zfs list -H -t snapshot -o name | grep "${ZFSDSET}@" | awk 'BEGIN{FS="@"};{print $2}' | grep $sstype > ${TMPFILE}

 case $sstype in
 H)  echo "Hourly Snapshot" >> $LOGFILE
   TODAY=`date +"%Y%m%d%H"`
   ;;
 D)  echo "Daily Snapshot" >> $LOGFILE
   ;;
 W)  echo "Weekly Snapshot" >> $LOGFILE
   ;;
 M)  echo "Monthly Snapshot" >> $LOGFILE
   ;;
 Q)  echo "Quaterly Snapshot" >> $LOGFILE
   ;;
 Y)  echo "Yearly Snapshot" >> $LOGFILE
   ;;
 *)  echo "sstype must be H | D | W | M | Q | Y " >> $LOGFILE
   exit 1
 esac

 #Snapshot
 if [ `cat ${TMPFILE} | grep $sstype$TODAY | wc -l | awk '{print $1}'` -gt 0 ]; then
  echo "Had snapshot($volpath $sstype$TODAY)." >> $LOGFILE
  rm -f ${TMPFILE}
  exit 1
 else
  echo "Take a snapshot of $volpath(${sstype}${TODAY})." >> $LOGFILE
  zfs snapshot `zfs list -H -o name ${volpath}`@${sstype}${TODAY}
 fi

 #Remove more old snapshot

 KEEPSSNUM=$maxnum
 REALSSNUM=`cat ${TMPFILE} | grep $sstype | wc -l`
 RMSSNUM=`expr $REALSSNUM - $KEEPSSNUM + 1`
 RMSSID=""

 ###echo $RMSSNUM

 if [ $RMSSNUM -gt 0 ]; then
  for RMSSID in `cat ${TMPFILE} | grep $sstype | sort -n | head -n $RMSSNUM`
  do
   echo "Remove old snapshot($volpath $RMSSID)." >> $LOGFILE
   zfs destroy `zfs list -H -o name ${volpath}`@$RMSSID
  done
 fi

elif [ $fstype = 'ufs' ]; then
 echo "UFS" >> $LOGFILE

 case $sstype in
 H) echo "Hourly Snapshot" >> $LOGFILE
  sskey='Hourly'
  ;;
 D) echo "Daily Snapshot" >> $LOGFILE
  sskey='Daily'
  ;;
 W) echo "Weekly Snapshot" >> $LOGFILE
  sskey='Weekly'
  ;;
 M) echo "Monthly Snapshot" >> $LOGFILE
  sskey='Monthly'
  ;;
 Q) echo "Quaterly Snapshot" >> $LOGFILE
  sskey='Quaterly'
  ;;
 Y) echo "Yearly Snapshot" >> $LOGFILE
  sskey='Yearly'
  ;;
 *) echo "sstype must be H | D | W | M | Q | Y " >> $LOGFILE
  exit 1
 esac
 
 #Snapshot
 echo "Take a snapshot UFS ${volpath}" >> $LOGFILE
 ${UFSSSCMD} make -g${maxnum} ${volpath}:${sskey}
else
 echo "Unsupported file system $fstype" >> $LOGFILE
fi

rm -f ${TMPFILE}

No comments: