#!/bin/bash # # bpcdump # Version: __appVersion__ # # Copyright (C) 2008-2012 by Titanium Mirror, Inc. # Author: R. Steve McKown # # Dumps the BPC VEID to external storage. It must have its storage on a # private filesystem mounted at /var/lib/vz/private/$VEID. # # A generalized version of this script should be created later. A recovery # option within this script should also be created. # CONSTANTS VEID=1158 VEDEV=/dev/vg0/ve$VEID VEMNT=/var/lib/vz/private/$VEID EXTFS=/media/esata unset WRITEPAR export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/usr/sbin:$PATH SCRIPT_EXT="conf start stop mount umount" CONF_DIR=/etc/vz/conf INFO=$(mktemp -q /tmp/bpcdump.XXXXX) # FUNCTIONS info() { if [ -n "$INFO" ]; then echo "$*" | tee -a "$INFO" else echo "$*" fi } error() { if [ -n "$INFO" ]; then echo "$*" | tee -a "$INFO" >&2 else echo "$*" fi } restartve() { if [ -n "$mounted" ]; then info "remounting VEID $VEID" mount $VEMNT && unset mounted fi if [ -n "$running" ]; then info "restarting VEID $VEID" vzctl start $VEID && unset running if [ $? = 0 ]; then info "VEID $VEID has been started" else error "VEID $VEID failed to start; backup continues" fi fi } cleanup() { ret="$1" shift msg="$*" [ -z "$ret" ] && ret=-1 [ -z "$msg" ] && msg=undef restartve if [ "$ret" = "0" ]; then info "Backup completed on $(date)" info "cleanup message: $msg" info "exit $ret" touch "$EXTVEIDFS/good" else error "Backup TERMINATED on $(date)" error "cleanup message: $msg" error "exit $ret" touch "$EXTVEIDFS/bad" fi [ -n "$backupwarn" ] && info "WARNINGS FOUND" >> "$INFO" exit $ret } # MAIN STARTDATE=$(date) cat > "$INFO" <<+EOF+ Date: $STARTDATE VEID: $VEID Volume: $VEDEV dd_rescue log: ddrlog dd_rescue bad blocks: ddrbb image file: image +EOF+ trap "cleanup 1 \"termination by signal\"" SIGINT SIGTERM if [ $(whoami) != "root" ]; then cleanup 1 "script requires super-user privileges" fi set $(vzctl status $VEID) unset exist mounted running backupwarn [ "$3" = "exist" ] && exist=1 [ "$4" = "mounted" ] && mounted=1 [ "$5" = "running" ] && running=1 if ! mount | grep -q "on $EXTFS"; then cleanup 1 "$EXTFS is not mounted" else info "$EXTFS is mounted" fi if [ -z "$exist" ]; then cleanup 1 "VEID $VEID does not exist" else info "VEID $VEID exists" fi if [ ! -d "$VEMNT" ]; then cleanup 1 "mount point for VEID $VEID does not exist" else info "VEID $VEID has private mount point" fi if ! grep -q "$VEMNT[ ]" /etc/fstab; then cleanup 1 "mount point for VEID $VEID not in /etc/fstab" fi if ! mount | grep -q "on $VEMNT"; then cleanup 1 "$VEMNT is not mounted" else info "VEID $VEID is mounted on $VEMNT" fi if [ -n "$running" ]; then info "stopping VEID $VEID" vzctl stop $VEID fi # Copy the VE's configuration file into its /etc/vzdump directory, as vzdump # does (for consistency) for file in $(echo "$SCRIPT_EXT"); do if [ -f "$file" ]; then destdir="${VEMNT}/etc/vzdump" mkdir -p "$destdir" info "Preserve config file ${VEID}.${SCRIPT_EXT}" cp "${CONF_DIR}/${VEID}.${SCRIPT_EXT}" "${destdir}/vps.${SCRIPT_EXT}" fi done # Unmount the filesystem, first getting its size if mount | grep -q "on $VEMNT"; then mounted=1 # duplicate; vzctl status told us... srcblks=$(df -P "$VEMNT" | grep "$VEMNT" | awk '{ print $2 }') # Add 5% buffer t=$((srcblks / 20)) srcblks=$((srcblks + t)) info "VEID fs contains $srcblks blocks" info "unmount VEID $VEID" umount "$VEMNT" else cleanup 1 "VEID private fs must be mounted to determine its size" fi # Before we begin writing, remove old backup dirs until we have room. # Assume backups for any VE are fair game for removal if space is needed. # Other disk contents shall not be removed. dstblks=$(df -P "$EXTFS" | grep "$EXTFS" | awk '{ print $4 }') while [ $dstblks -le $srcblks ]; do info "Only $dstblks free on $EXTFS" oldest=$(cd $EXTFS && eval ls -td "ve[0-9]*" 2>/dev/null | tail -1) if [ -z "$oldest" ]; then cleanup 1 "out of space: need $srcblks KB, have $dstblks KB" elif [ -d "$EXTFS/$oldest" ]; then info "Removing old backup $oldest from $EXTFS" rm -rf "$EXTFS/$oldest" else cleanup 1 "Structure error on $EXTFS. Correct manually." fi dstblks=$(df -P "$EXTFS" | grep "$EXTFS" | awk '{ print $4 }') done if [ $dstblks -le $srcblks ]; then cleanup 1 "out of space: need $srcblks KB, have $dstblks KB" fi info "Archive space ok: need $srcblks KB, have $dstblks KB" EXTVEIDFS="$EXTFS/ve$VEID-$(date +'%Y%m%d')" if [ -d "$EXTVEIDFS" ]; then rm -rf "${EXTVEIDFS}.old" mv "$EXTVEIDFS" "${EXTVEIDFS}.old" else rm -rf "$EXTVEIDFS" fi mkdir "$EXTVEIDFS" || cleanup 1 "cannot mkdir $EXTVEIDFS/" cd "$EXTVEIDFS" || cleanup 1 "cannot cd into $EXTVEIDFS/" echo "$STARTDATE" > "$EXTVEIDFS/begin" # Move temporary INFO file to its permanent home within $EXTVEIDFS mv "$INFO" "$EXTVEIDFS/info" || cleanup 1 "cannot mv file to $EXTVEIDFS/" INFO="$EXTVEIDFS/info" info "copy $VEID device $VEDEV to $EXTVEIDFS/image" time dd_rescue -Aqy 8192 -l "$EXTVEIDFS/ddrlog" -o "$EXTVEIDFS/ddrbb" \ $VEDEV "$EXTVEIDFS/image" ret=$? if [ "$ret" != "0" ]; then backupwarn=1 error "WARNING: dd_rescue returned $ret" fi info "calculate md5sum for $VEDEV (src)" srcmd5=$(md5sum "$VEDEV" 2>&1 | awk '{ print $1 }') info "calculate md5sum for image (dst)" # We're done with the partition. We can restart the VE now. restartve # Continue on with archive and validation (cd "$EXTVEIDFS" && md5sum image >image.md5sum 2>&1 | awk '{ print $1 }') dstmd5=$(md5sum "$EXTVEIDFS/image" 2>&1 | awk '{ print $1 }') echo "$dstmd5 image.md5sum" > "$EXTVEIDFS/image.md5sum" info "$srcmd5 source md5sum" info "$dstmd5 dest md5sum" if [ "$srcmd5" != "$dstmd5" -o -z "$srcmd5" ]; then backupwarn=1 error "WARNING: md5 signatures do not match" else info "md5 signatures match" fi if [ -n "$WRITEPAR" ]; then (cd "$EXTVEIDFS" && time par2 c img) ret=$? if [ "$ret" != "0" ]; then backupwarn=1 info "WARNING: redundancy failed: par2 returned $ret" fi (cd "$EXTVEIDFS" && time par2 v img) ret=$? if [ "$ret" != "0" ]; then backupwarn=1 info "WARNING: redundancy inexact: par2 returned $ret" fi fi cleanup 0 "successful" # vi: set shiftwidth=4: