Простая "обёртка" для LVMSync

BASH
Написал незамысловатый фронтэнд для замечательной утилиты lvmsync, написанной Matt Shed. Спасибо тебе, Шэд, ты единственный человек, который удосужился разумным (т.е. читай: вменяемым) способом решить вопрос синхронизации блочных устройств. Да, только для LVM-томов. Но причина тому банальна до безобразия: LVM-тома — это пока единственный широко распространённый тип блочных устройств, изменения на которых можно отслеживать при посредстве самого механизма записи, а не выявлять каким-то хитрым образом уже пост-фактум, считывая произвольные куски, скурпулёзно высчитывая контрольные суммы и вообще занимаясь какой-то хиромантией. Есть конечно ddsnap от Zumastor'а, и он нашёл своё широкое применение на хранилищах свалок истории, предлагая патчить ядро Linux для решения «в общем виде» той задачи, которая в принципе такого решения иметь не должна.

Итак, собственно скрипт фронтэнда…
Не пинайте за примитивизм и кривой псевдоинглиш, цель скрипта — просто показать возможную реализацию самой идеи lvmsync'а: для логического тома, уже имеющего снэпшот, существующий неизвестно сколько времени, создаём ещё один «свежий» снэпшот, фиксирующий изменения на момент, непосредственно предшествующий синхронизации, делаем синхронизацию и после этого заменяем «старый» снэпшот на «новый». В идеале нужно бы останавливать на период синхронизации всю запись на исходный логический том, но вы сможете добавить соотв. код и сами.
(Примечание: в скрипте используются мои debug-функции типа error_, info_ и проч. Их нужно заменить на echo, либо написать простенькие функции-заглушки с тем же echo)

#!/bin/bash
slf=${0##*/}
getHomeDir () {
# We need this hack because sudo sucks and it cant correctly set the environment for the destination user account
 getent passwd $(whoami) | cut -d: -f6
 return 0
}
doShowUsage () {
 cat <<EOF
Usage: $slf -s sourceLogicalVolume -d destLogicalVolume [ [-H hostName] [-D divideFactor] ]
Where:
sourceLogicalVolume - must be snapshot of real lv
destLogicalVolume - where to write changes fixed in snapshot
hostName - destination host name or ip
divideFactor - substitution (actualized) snapshot will be created with size = (real logical volume size)/divideFactor
EOF
 return 0
}
# Log often, debug better ->
pthIncludeFunctions='/opt/sa-scripts/scripts/functions'
source $pthIncludeFunctions/resolver
resolve_deps dbg
# Debug level may be: NONE, FATAL, ERROR, WARNING, NOTICE, INFO, DEBUG
DEBUG_LEVEL=INFO
# <-

hostName=
while getopts 's:d:H:D:' opt; do
 case $opt in
 s) srcLv="$OPTARG" ;;
 d) dstLv="$OPTARG" ;;
 H) hostName="$OPTARG" ;;
 D) div="$OPTARG" ;;
 \?) doShowUsage; exit 1 ;; 
 esac
done
div=${div:-10}

(( $(id -u) )) && fatal_ "This utility require to be runned under some account with UID=0"
[[ -b $srcLv ]] || fatal_ "Source logical volume (snapshot) $srcLv doesnt exist"
[[ -b $dstLv ]] || fatal_ "Destination logical volume $srcLv doesnt exist"
[[ $srcLv =~ ^/dev/([^/]+)/snap-.+$ ]] || fatal_ 'Source (snapshot) logical volume must be named as snap-<SnapedLogicalVolumeName>!'
srcVgName=${BASH_REMATCH[1]}
[[ $div =~ ^[0-9]+$ && ! $div == 0 ]] || fatal_ 'divideFactor must be an integer greater than zero!'


myHome="$(getHomeDir)"
if ! [[ -f ${myHome}/.ssh/id_rsa.pub ]]; then
 error_ 'You have to create your SSH keyring first!'
 ssh-keygen -t rsa
fi

if ! [[ $hostName ]]; then
 fgrep -q "$(<${myHome}/.ssh/id_rsa.pub)" ${myHome}/.ssh/authorized_keys || \
  cat ${myHome}/.ssh/id_rsa.pub >> ${myHome}/.ssh/authorized_keys
fi


srcLvReal=${srcLv/snap-/}
realLvSize=$(lvs -o lv_size --units k --noheadings $srcLvReal | sed -nr 's%^\s*([0-9]+).+$%\1%p')
info_ "Creating checkpoint with new snapshot volume \"${srcLv}-new\"..."
if [[ -b ${srcLv}-new ]]; then
 info_ "The LV with name ${srcLv}-new conflicting with our actualized snapshot name, so we have to delete them..."
 lvremove -f ${srcLv}-new || fatal_ "Cant remove ${srcLv}-new for some reason (see above why), exiting"
fi
lvcreate -s -L $((realLvSize/div))k -n ${srcLv}-new $srcLvReal || \
 fatal_ "Cant create checkpoint, exiting"
info_ 'Good, checkpoint was created'
info_ "Do lvmsync from $srcLv to ${hostName:+$hostName:}$dstLv. Big thanks to Matt Shed for this utility (http://theshed.hezmatt.org/lvmsync/)"'!'
if lvmsync $srcLv ${hostName:-localhost}:$dstLv; then
 info_ 'OK'
 lvremove -f $srcLv
 lvrename ${srcLv}-new $srcLv
else
 error_ "lvmsync failed"
 lvremove -f ${srcLv}-new
fi


Кстати, у Matt'а почему-то неверно написана конструкция case, вот своеобразный «патч» (":" на «then» заменяет):

--- mpalmer-lvmsync-9177191/lvmsync	2012-02-06 00:14:50.000000000 +0400
+++ /usr/bin/lvmsync	2012-04-09 15:21:50.000000000 +0400
@@ -258,15 +258,15 @@
 # of dmsetup ls
 def canonicalise_dm(origname)
 	case origname
-		when %r{^/dev/mapper/(.+)$}:
+		when %r{^/dev/mapper/(.+)$} then
 			$1
-		when %r{^/dev/([^/]+)/(.+)$}:
+		when %r{^/dev/([^/]+)/(.+)$} then
 			vg = $1
 			lv = $2
 			vg.gsub('-', '--') +
 			'-' +
 			lv.gsub('-', '--')
-		when %r{^([^/]+)/(.*)$}:
+		when %r{^([^/]+)/(.*)$} then
 			vg = $1
 			lv = $2
 			vg.gsub('-', '--') +

2 комментария

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.