MYCSS

2020-03-29

Нотатка: zfs replication to external usb drive


Нотатка для себе, так я роблю реплікацію з зовнішнім USB накопичувачем у FreeNAS.
Зовнішній USB накопичувач монтується безпосередньо перед реплікацією, і розмонтовується після реплікації.
Зовнішній диск монтується за GPT ідентифікацією диску - GPTID (zpool list -v extusb-01), та ідентифікацією zfs pool за POOL_GUID (zpool list -o guid extusb-01).
Зовнішній диск був створений майстром створення zfs pool у FreeNAS.
Скрипт /root/script/backup-2-extusb-01-next.sh  запускається за розкладом через cron.


backup-2-extusb-01-next.sh

#!/bin/sh

GPTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
POOL_GUID=yyyyyyyyyyyyyyyyyyy
EXTPOOL="extusb-01"
MNTPOINT="/mnt"
SRCPOOL="pool"
SRCDATASETS=""
#use skipdatasets via | separator
SRCDATASETSSKIP="^pool/SOME|^pool/SOMEOTHER"
DSTDATASETROOT=${EXTPOOL}/backup SAVEOLDSNAPHOTS=10 /root/script/mount_ext.sh zpool status -x ${EXTPOOL} if [ $? -gt 0 ];then echo "Try import ${EXTPOOL}" zpool import ${EXTPOOL} -R ${MNTPOINT} echo "result:" $? zpool status -x ${EXTPOOL} if [ $? -gt 0 ];then echo "can't import pool ${EXTPOOL}" exit fi fi echo backup start... $(date) SRCDATASETS=$(zfs list -H -o name | egrep "^${SRCPOOL}" | egrep -v "${SRCDATASETSSKIP}") SNAPDATE=$(date +%Y%m%d%H%M%S) SNAPNAME1=snap_${EXTPOOL}_ SNAPNAME=${SNAPNAME1}${SNAPDATE} echo LIST of ${SRCPOOL} SRCPOOLLIST=$(zfs list -H -o name |egrep "^${SRCPOOL}/") for sppool in ${SRCPOOLLIST}; do echo ------ echo sppool ${sppool} datasetpath=$(echo ${sppool} | sed -e "s/^${SRCPOOL}\///g") echo datasetpath ${datasetpath} SRCSNAPLIST=$(zfs list -H -s creation -o name -t snapshot | egrep "^${SRCPOOL}/" | grep ${sppool}@${SNAPNAME1} | tail -1) SRCSNAPNAME=$(echo ${SRCSNAPLIST} | awk -F@ '{print $2}') echo SSNAP ${SRCSNAPLIST} @ ${SRCSNAPNAME} DSTSNAPLIST=$(zfs list -H -s creation -o name -t snapshot | egrep "^${EXTPOOL}/" | grep "${datasetpath}@${SNAPNAME1}" | tail -1) DSTSNAPNAME=$(echo ${DSTSNAPLIST} | awk -F@ '{print $2}') echo DSNAP ${DSTSNAPLIST} @ ${DSTSNAPNAME} if [ "${SRCSNAPNAME}" == "${DSTSNAPNAME}" ];then zfs snapshot ${sppool}@${SNAPNAME} zfs hold keep ${sppool}@${SNAPNAME} if [ "$?" -eq 0 ];then echo incremental send -i ${SRCSNAPNAME} ${sppool}@${SNAPNAME} , receive -F ${DSTDATASETROOT}/${datasetpath} zfs send -i ${SRCSNAPNAME} ${sppool}@${SNAPNAME} | zfs receive -F ${DSTDATASETROOT}/${datasetpath} if [ "$?" -eq 0 ];then echo destroy old snap "${sppool}@${SRCSNAPNAME}" zfs release keep "${sppool}@${SRCSNAPNAME}" zfs destroy "${sppool}@${SRCSNAPNAME}" echo result $? fi fi else echo "***************************************************" echo src pool: ${sppool} SNAP NOT EQ "${SRCSNAPNAME}" and "${DSTSNAPNAME}" echo "***************************************************" sleep 15 echo "** DO FIRST COPY **********************************************" echo "SNAP zfs snapshot ${sppool}@${SNAPNAME}" zfs snapshot ${sppool}@${SNAPNAME} echo "HOLD zfs hold keep ${sppool}@${SNAPNAME}" zfs hold keep ${sppool}@${SNAPNAME} echo "DESTROY DEST zfs destroy - ${DSTDATASETROOT}/${datasetpath} " zfs destroy -r ${DSTDATASETROOT}/${datasetpath} echo "SEND zf send ${sppool}@${SNAPNAME} | zfs receive ${DSTDATASETROOT}/${datasetpath}" zfs send ${sppool}@${SNAPNAME} | zfs receive ${DSTDATASETROOT}/${datasetpath} echo "***************************************************" sleep 15 fi #destroy old snapshots DATASETOLDSNAP=${DSTDATASETROOT}/${datasetpath} echo try remove old snapshots on: ${DATASETOLDSNAP} saving: ${SAVEOLDSNAPHOTS} zfs list -H -t snapshot -o name -S creation -r ${DATASETOLDSNAP} | grep ^${DATASETOLDSNAP}@ | tail +${SAVEOLDSNAPHOTS} | xargs -n 1 zfs destroy done SRCSNAPLIST=$(zfs list -H -s creation -o name -t snapshot |egrep "^${SRCPOOL}/" |grep ${SNAPNAME1}) echo LIST of $EXTPOOL zfs list -H -o name -t snapshot |egrep "^${EXTPOOL}/" |grep ${SNAPNAME1} /root/script/unmount_ext.sh echo backup done... $(date) exit

/root/script/mount_ext.sh 

Скрипт виконує монтування зашифрованого тому через GELI.
Ключ диску зберігається у теці /root/.key з іменем geli-${EXTPOOL}.key, де EXTPOOL ім'я зовнішнього zfs pool.
#!/bin/sh

GPTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
POOL_GUID=yyyyyyyyyyyyyyyyyyy
EXTPOOL="extusb-01"

geli_device="gptid/${GPTID}"
geli_flags="-k /root/.key/geli-${EXTPOOL}.key -p"

MNTPOINT="/mnt"
SRCPOOL="pool"
echo GELI ATTACH
geli attach ${geli_flags} ${geli_device}
echo "result:" $?

zpool status -x ${EXTPOOL}
if [ $? -gt 0 ];then
 echo "Try import ${EXTPOOL}"
 zpool import ${EXTPOOL} -R ${MNTPOINT}
 echo "result:" $?
 zpool status -x ${EXTPOOL}
 if [ $? -gt 0 ];then
  echo "can't import pool ${EXTPOOL}"
  exit
 fi
fi

exit

/root/script/unmount_ext.sh

#!/bin/sh

GPTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
POOL_GUID=yyyyyyyyyyyyyyyyyyy
EXTPOOL="extusb-01"

geli_device="gptid/${GPTID}"

MNTPOINT="/mnt"
SRCPOOL="poolz2"

snapshots=$(zfs list -t snapshot | grep ^${EXTPOOL}/backup/BACKUP@snap_${EXTPOOL} | wc -l)
zpool list ${EXTPOOL} | mail -s "Ext USB ZFS pool "${EXTPOOL}" - used space, snaphots: ${snapshots}" postmaster@email

echo "Try export ${EXTPOOL}"
zpool export ${EXTPOOL}
echo "result:" $?

echo GELI DETTACH
geli detach ${geli_device}
echo "result:" $?
exit

Засипання зовнішнього диску

Я використовую Seagate Expansion 10TB для зовнішнього диску. І стала потреба щоб він вимикався через певний час після використання.
Seagate Expansion 10TB
Стандартні рішення від опреаційної системи не дають результату, томущо виробник забокував цю можливість. І рішення тільки використтаи спеціальну программу від Seagate для налаштування параметрів зовнішніх дисків, на зараз не помню вже назви, але з під Windows прийшлось це робити.
І тількт так зараз цей накопичувач засипає після завершення реплікації автоматично.

Зачистка 

Всяк буває і інколи треба зачисити snapshots @snap_${EXTPOOL}  котрі "залипли".
Цей скрипт залишає тільку одну останню версію snapshots @snap_${EXTPOOL} , і якщо вона ще є зблокованна від видалення через zfs hold, тоді snapshot розблокується перед видаленням.

/root/script/clear_holded_snapshots.sh
#!/bin/sh

SRCPOOL="pool"
EXTPOOL="extusb-01"
HOLDTAG="keep"

datas=$(zfs list -H  -o name -r ${SRCPOOL}  )

for data in ${datas}; do
 echo *${data}
 snapshots=$(zfs list -H  -S creation -o name -t snapshot -r ${data} | grep ^${data}@snap_${EXTPOOL} | tail -n +2)
 for sn in ${snapshots}; do
#   echo ${sn}
   holded=$(zfs holds -H ${sn} | grep ${HOLDTAG})
   if [ ! -z "${holded}" ];then
      echo HOLDED ${sn}, releasing
      zfs release ${HOLDTAG} ${sn}
   fi
   echo zfs destroy ${sn}
   zfs destroy ${sn}
 done
done

S.M.A.R.T. test

Так як диск майже завжи вимкенно, то можна після кожної реплікації виконати перевірку диску через наступний скрипт.
#!/bin/sh

GPTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
disk=$(glabel status | grep ${GPTID}| awk '{print $3}' | awk -Fp '{print $1}')
#echo ${disk}
smartctl -q errorsonly -t short /dev/${disk}


Немає коментарів:

Коли забув ти рідну мову, біднієш духом ти щодня...
When you forgot your native language you would become a poor at spirit every day ...

Д.Білоус / D.Bilous
Рабів до раю не пускають. Будь вільним!

ipv6 ready