Нотатка: 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 для налаштування параметрів зовнішніх дисків, на зараз не помню вже назви, але з під 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}

