diff options
author | Mike Snitzer <snitzer@redhat.com> | 2009-05-14 16:46:12 +0000 |
---|---|---|
committer | Mike Snitzer <snitzer@redhat.com> | 2009-05-14 16:46:12 +0000 |
commit | 761e5741906cf8bd857b65292df4b1fb6a26f991 (patch) | |
tree | 8f8d7adeec49621b343b179e32e04059d2d8883c /scripts/vgimportclone.sh | |
parent | 970f241c5230554f4e43e292a3bf283d7b6169bd (diff) | |
download | lvm2-761e5741906cf8bd857b65292df4b1fb6a26f991.tar.gz lvm2-761e5741906cf8bd857b65292df4b1fb6a26f991.tar.xz lvm2-761e5741906cf8bd857b65292df4b1fb6a26f991.zip |
Add vgimportclone and install it and the man page by default.
Diffstat (limited to 'scripts/vgimportclone.sh')
-rwxr-xr-x | scripts/vgimportclone.sh | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/scripts/vgimportclone.sh b/scripts/vgimportclone.sh new file mode 100755 index 00000000..66afd27c --- /dev/null +++ b/scripts/vgimportclone.sh @@ -0,0 +1,334 @@ +#!/bin/sh + +# Copyright (C) 2009 Chris Procter All rights reserved. +# Copyright (C) 2009 Red Hat, Inc. All rights reserved. +# +# This file is part of LVM2. +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions +# of the GNU General Public License v.2. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# vgimportclone: This script is used to rename the VG and change the associated +# VG and PV UUIDs (primary application being HW snapshot restore) + +# following external commands are used throughout the script +# echo and test are internal in bash at least +RM=rm +BASENAME=basename +MKTEMP=mktemp +AWK=awk +CUT=cut +TR=tr +READLINK=readlink +GREP=grep +GETOPT=getopt + +# user may override lvm location by setting LVM_BINARY +LVM="${LVM_BINARY:-lvm}" + +die() { + code=$1; shift + echo "Fatal: $@" 1>&2 + exit $code +} + +"$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'" + + +function getvgname { +### get a unique vg name +### $1 = list of exists VGs +### $2 = the name we want + VGLIST=$1 + VG=$2 + NEWVG=$3 + + BNAME="${NEWVG:-${VG}}" + NAME="${BNAME}" + I=0 + + while [[ "${VGLIST}" =~ "${NAME}" ]] + do + I=$(($I+1)) + NAME="${BNAME}$I" + done + echo "${NAME}" +} + + +function checkvalue { +### check return value and error if non zero + if [ $1 -ne 0 ] + then + die $1 "$2, error: $1" + fi +} + + +function usage { +### display usage message + echo "Usage: ${SCRIPTNAME} [options] PhysicalVolume [PhysicalVolume...]" + echo " -n|--basevgname - Base name for the new volume group(s)" + echo " -i|--import - Import any exported volume groups found" + echo " -t|--test - Run in test mode" + echo " --quiet - Suppress output" + echo " -v|--verbose - Set verbose level" + echo " -d|--debug - Set debug level" + echo " --version - Display version information" + echo " -h|--help - Display this help message" + echo "" + exit 1 +} + + +function cleanup { + #set to use old lvm.conf + LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR} + + "$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}" +} + +SCRIPTNAME=`"$BASENAME" $0` + + +if [ "$UID" != "0" -a "$EUID" != "0" ] +then + die 3 "${SCRIPTNAME} must be run as root." +fi + +LVM_OPTS="" +TEST_OPT="" +DISKS="" +# for compatibility: using mktemp -t rather than --tmpdir +TMP_LVM_SYSTEM_DIR=`"$MKTEMP" -d -t snap.XXXXXXXX` +IMPORT=0 +DEBUG="" +VERBOSE="" +DEVNO=0 + +if [ -n "${LVM_SYSTEM_DIR}" ]; then + export ORIG_LVM_SYS_DIR="${LVM_SYSTEM_DIR}" +fi + +trap cleanup 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 + +##################################################################### +### Get and check arguments +##################################################################### +OPTIONS=`"$GETOPT" -o n:dhitv \ + -l basevgname:,debug,help,import,quiet,test,verbose,version \ + -n "${SCRIPTNAME}" -- "$@"` +[ $? -ne 0 ] && usage +eval set -- "$OPTIONS" + +while true +do + case $1 in + -n|--basevgname) + NEWVG="$2"; shift; shift + ;; + -i|--import) + IMPORT=1; shift + ;; + -t|--test) + TEST_OPT="-t" + shift + ;; + --quiet) + LVM_OPTS="--quiet ${LVM_OPTS}" + shift + ;; + -v|--verbose) + if [ -z "$VERBOSE" ] + then + VERBOSE="-v" + else + VERBOSE="${VERBOSE}v" + fi + shift + ;; + -d|--debug) + if [ -z "$DEBUG" ] + then + DEBUG="-d" + set -x + else + DEBUG="${DEBUG}d" + fi + shift + ;; + --version) + "$LVM" version + shift + exit 0 + ;; + -h|--help) + usage; shift + ;; + --) + shift; break + ;; + *) + usage + ;; + esac +done + +# process remaining arguments (which should be disks) +for ARG +do + if [ -b "$ARG" ] + then + ln -s "$ARG" ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO} + DISKS="${DISKS} ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}" + DEVNO=$((${DEVNO}+1)) + else + die 3 "$ARG is not a block device." + fi +done + +# setup LVM_OPTS +if [ -n "${DEBUG}" -o -n "${VERBOSE}" ] +then + LVM_OPTS="${LVM_OPTS} ${DEBUG} ${VERBOSE}" +fi + +### check we have suitable values for important variables +if [ -z "${DISKS}" ] +then + usage +fi + +##################################################################### +### Get the existing state so we can use it later +##################################################################### + +OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null` +checkvalue $? "Current VG names could not be collected without errors" + +##################################################################### +### Prepare the temporary lvm environment +##################################################################### + +for BLOCK in ${DISKS} +do + FILTER="\"a|^${BLOCK}$|\", ${FILTER}" +done +export FILTER="filter=[ ${FILTER} \"r|.*|\" ]" + +LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf + +"$LVM" dumpconfig ${LVM_OPTS} | \ +"$AWK" -v DEV=${TMP_LVM_SYSTEM_DIR} -v CACHE=${TMP_LVM_SYSTEM_DIR}/.cache \ + -v CACHE_DIR=${TMP_LVM_SYSTEM_DIR}/cache \ + '/^[[:space:]]*filter[[:space:]]*=/{print ENVIRON["FILTER"];next} \ + /^[[:space:]]*scan[[:space:]]*=/{print "scan = [ \"" DEV "\" ]";next} \ + /^[[:space:]]*cache[[:space:]]*=/{print "cache = \"" CACHE "\"";next} \ + /^[[:space:]]*cache_dir[[:space:]]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \ + {print $0}' > ${LVMCONF} + +checkvalue $? "Failed to generate ${LVMCONF}" + +# verify the config contains the filter, scan and cache_dir (or cache) config keywords +"$GREP" -q '^[[:space:]]*filter[[:space:]]*=' ${LVMCONF} || \ + die 5 "Temporary lvm.conf must contain 'filter' config." +"$GREP" -q '^[[:space:]]*scan[[:space:]]*=' ${LVMCONF} || \ + die 6 "Temporary lvm.conf must contain 'scan' config." + +# check for either 'cache' or 'cache_dir' config values +"$GREP" -q '[[:space:]]*cache[[:space:]]*=' ${LVMCONF} +CACHE_RET=$? +"$GREP" -q '^[[:space:]]*cache_dir' ${LVMCONF} +CACHE_DIR_RET=$? +[ $CACHE_RET -eq 0 -o $CACHE_DIR_RET -eq 0 ] || \ + die 7 "Temporary lvm.conf must contain 'cache' or 'cache_dir' config." + +### set to use new lvm.conf +export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR} + + +##################################################################### +### Rename the VG(s) and change the VG and PV UUIDs. +##################################################################### + +PVINFO=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator : 2>/dev/null` +checkvalue $? "PV info could not be collected without errors" + +# output VG info so each line looks like: name:exported?:disk1,disk2,... +VGINFO=`echo "${PVINFO}" | \ + "$AWK" -F : '{{sub(/^[[:space:]]*/,"")} \ + {vg[$2]=$1","vg[$2]} if($3 ~ /^..x/){x[$2]="x"}} \ + END{for(k in vg){printf("%s:%s:%s\n", k, x[k], vg[k])}}'` +checkvalue $? "PV info could not be parsed without errors" + +for VG in ${VGINFO} +do + VGNAME=`echo "${VG}" | "$CUT" -d: -f1` + EXPORTED=`echo "${VG}" | "$CUT" -d: -f2` + PVLIST=`echo "${VG}" | "$CUT" -d: -f3- | "$TR" , ' '` + + if [ -z "${VGNAME}" ] + then + FOLLOWLIST="" + for DEV in $PVLIST; do + FOLLOW=`"$READLINK" $DEV` + FOLLOWLIST="$FOLLOW $FOLLOWLIST" + done + die 8 "Specified PV(s) ($FOLLOWLIST) don't belong to a VG." + fi + + if [ -n "${EXPORTED}" ] + then + if [ ${IMPORT} -eq 1 ] + then + "$LVM" vgimport ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" + checkvalue $? "Volume Group ${VGNAME} could not be imported" + else + echo "Volume Group ${VGNAME} exported, skipping." + continue + fi + fi + + ### change the pv uuids + if [[ "${PVLIST}" =~ "unknown" ]] + then + echo "Volume Group ${VGNAME} incomplete, skipping." + continue + fi + + for BLOCKDEV in ${PVLIST} + do + "$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid ${BLOCKDEV} --config 'global{activation=0}' + checkvalue $? "Unable to change PV uuid for ${BLOCKDEV}" + done + + NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"` + + "$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid "${VGNAME}" --config 'global{activation=0}' + checkvalue $? "Unable to change VG uuid for ${VGNAME}" + + ## if the name isn't going to get changed dont even try. + if [ "${VGNAME}" != "${NEWVGNAME}" ] + then + "$LVM" vgrename ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" "${NEWVGNAME}" + checkvalue $? "Unable to rename ${VGNAME} to ${NEWVGNAME}" + fi + +done + +##################################################################### +### Restore the old environment +##################################################################### +### set to use old lvm.conf +LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR} + +### update the device cache and make sure all +### the device nodes we need are straight +"$LVM" vgscan ${LVM_OPTS} --mknodes + +exit 0 |