Hi, After getting kicking from Alasdair at a conference a few weeks ago for asking him about Netapp snapshots I decided it would by useful to implement http://sources.redhat.com/lvm2/wiki/HardwareSnapshotRestore (step 5 onwards) as a script. I've tested it on RHEL 5 and it seems pretty solid but I don't quite know the best way to release it to the world so here it is, all comments and advice gratefully received :) I will get around to writing a man page, but in the meantime 1) present in your clone luns 2) figure out what devices they appear as 3) run importclone /dev/sda /dev/sdb /dev/sdc (replacing /dev/sda etc by your clone luns obviously) If your VG is called myvg you should now also have a new vg called myvg.1 with different uuids. It will ignore incomplete volume groups, or exported volume groups unless the -i flag is used. chris P.S. I'm using ascii 001 and 002 characters as seperators which might get mangled by email sorry :( ################# importclone ############################# !/bin/sh # Copyright (C) 2009 Chris Procter All rights reserved. # 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 exec 2> ./$0.log set -x function appenddisk { ### add a blockdevice path (/dev/sda etc) to a list if its valid LIST=$1 DISK=$2 if [ ! -b "${DISK}" ] then echo " ${DISK} not a valid block device - ignoring" >&2 echo "${LIST}" return fi if [ -z "${LIST}" ] then LIST="${DISK}" else LIST="${LIST} ${DISK}" fi echo ${LIST} } function getvgname { ### get a unique vg name ### $1 = list of exists VGs ### $2 = the name we want VGLIST=$1 VG=$2 NEWVG=$3 BASENAME="${NEWVG:-${VG}}" NAME="${BASENAME}" I=0 while [[ "${VGLIST}" =~ "${NAME}" ]] do I=$(($I+1)) NAME="${BASENAME}.$I" done echo "${NAME}" } function checkvalue { ### check return value and error if non zero if [ $1 -ne 0 ] then echo "FAIL!: $2 value: $1" exit $1 fi } function usage { ### display usage message SCRIPT=`basename $0` echo "${SCRIPT} - Restore LVM data from a hardware snapshot" echo -e "Usage: ${SCRIPT} [disk1...]" echo -e "\t\t-h\t\t- Display this usage message" echo -e "\t\t-i\t\t- Import any exported volume groups found" echo -e "\t\t-n\t\t- Name for the new volume group(s)" echo -e "\t\t-l [path]\t - location of lvm.conf (default ${LVMCONF})" echo -e "\t\t-t [path]\t - directory for temporary lvm directory (default ${TMPDIR})" exit 0 } function cleanup { #set to use old lvm.conf LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR} } SHOW=0 DISKS="" LVMCONF="/etc/lvm/lvm.conf" TMPDIR="/tmp/lvm" NOVGFLAG=0 IMPORT=0 export ORIG_LVM_SYS_DIR=${LVM_SYSTEM_DIR} 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 ##################################################################### while [ $# -ne 0 ] do case $1 in -h) usage shift ;; -i) IMPORT=1 shift ;; -l) LVMCONF="$2" shift shift ;; -t) TMPDIR="$2" shift shift ;; -n) NEWVG="$2" shift shift ;; *) DISKS=`appenddisk "${DISKS}" "$1"`; shift ;; esac done ### check we have suitable values for important variables if [ -z "${DISKS}" ] then usage fi ##################################################################### ### Get the existing state so we can use it later ##################################################################### #pvs --noheadings --trustcache 2>/dev/null OLDVGS=`pvs --noheadings --trustcache 2>/dev/null | awk '(NF==6){printf("%s ",$2)}'` ##################################################################### ### Prepare the temporay lvm environment ##################################################################### if [ ! -d "${TMPDIR}" ] then mkdir "${TMPDIR}" checkvalue $? "Unable to create ${TMPDIR}" fi ###create filter for BLOCK in ${DISKS} do FILTER="\"a|^${BLOCK}$|\",${FILTER}" done FILTER="filter=[ ${FILTER} \"r|.*|\" ]" awk -v var="${FILTER}" '/^[[:space:]]*filter/{print var;next};{print $0}' < ${LVMCONF} > ${TMPDIR}/lvm.conf ### set to use new lvm.conf export LVM_SYSTEM_DIR=${TMPDIR} ##################################################################### ### Change the uuids. ##################################################################### PVSCAN=`pvscan` VGS=`echo "${PVSCAN}" |awk '$1~/PV/{for(i=1;i<=NF;i++){if($i=="VG"){vg[$(i+1)]=vg[$(i+1)]""$2}if($i=="exported"){x[$(i+2)]="x"}}}END{for(k in vg){printf k""x[k]""vg[k]" "}}'` echo "$VGS" for VG in ${VGS} do VGNAME=`echo -e "${VG}" |cut -d -f1` EXPORTED=`echo -e "${VG}" | cut -d -f2` PVLIST=`echo -e "${VG}" | cut -d -f3` if [ -n "${EXPORTED}" ] then if [ ${IMPORT} -eq 1 ] then vgimport ${VGNAME} else echo "Volume Group ${VGNAME} exported, skipping." continue fi fi ### change the pv uuids BLOCKDEVS=`echo ${PVLIST} | tr '' ' '` if [ "${PVLIST}" =~ "unknown" ] then echo "Volume Group ${VGNAME} incomplete, skipping." continue fi for BLOCKDEV in ${BLOCKDEVS} do pvchange --uuid ${BLOCKDEV} --config 'global{activation=0}' checkvalue $? "Unable to change pvuuid for ${BLOCKDEV}" done NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"` vgchange --uuid ${VGNAME} --config 'global{activation=0}' checkvalue $? "Unable to change vguuid for ${VGNAME}" ## if the name isn't going to get changed dont even try. if [ "${VGNAME}" != "${NEWVGNAME}" ] then vgrename "${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} ### make sure all the device nodes we need are straight vgmknodes >/dev/null ### sort out caches. pvscan exit 0 _______________________________________________ linux-lvm mailing list linux-lvm@redhat.com https://www.redhat.com/mailman/listinfo/linux-lvm read the LVM HOW-TO at http://tldp.org/HOWTO/LVM-HOWTO/