mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
75420282e1
Make sure log/prefix is set to "" when getting the list of VG names. We need this for the format to be correct so it's properly searched through later on.
340 lines
9.4 KiB
Bash
Executable File
340 lines
9.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright (C) 2009 Chris Procter All rights reserved.
|
|
# Copyright (C) 2009-2015 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
|
|
READLINK=readlink
|
|
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}
|
|
|
|
if [ $KEEP_TMP_LVM_SYSTEM_DIR -eq 1 ]; then
|
|
echo "${SCRIPTNAME}: LVM_SYSTEM_DIR (${TMP_LVM_SYSTEM_DIR}) must be cleaned up manually."
|
|
else
|
|
"$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}"
|
|
fi
|
|
}
|
|
|
|
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`
|
|
KEEP_TMP_LVM_SYSTEM_DIR=0
|
|
CHANGES_MADE=0
|
|
IMPORT=0
|
|
DEBUG=""
|
|
VERBOSE=""
|
|
VERBOSE_COUNT=0
|
|
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)
|
|
let VERBOSE_COUNT=VERBOSE_COUNT+1
|
|
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
|
|
|
|
# turn on DEBUG (special case associated with -v use)
|
|
if [ -z "$DEBUG" -a $VERBOSE_COUNT -gt 3 ]; then
|
|
DEBUG="-d"
|
|
set -x
|
|
fi
|
|
|
|
# setup LVM_OPTS
|
|
if [ -n "${DEBUG}" -o -n "${VERBOSE}" ]
|
|
then
|
|
LVM_OPTS="${LVM_OPTS} ${DEBUG} ${VERBOSE}"
|
|
fi
|
|
|
|
# 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
|
|
|
|
### check we have suitable values for important variables
|
|
if [ -z "${DISKS}" ]
|
|
then
|
|
usage
|
|
fi
|
|
|
|
#####################################################################
|
|
### Get the existing state so we can use it later.
|
|
### The list of VG names is saved in this format:
|
|
### :vgname1:vgname2:...:vgnameN:
|
|
#####################################################################
|
|
|
|
OLDVGS=":`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings --rows --separator : --config 'log{prefix=""}'`:"
|
|
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
|
|
|
|
CMD_CONFIG_LINE="devices { \
|
|
scan = [ \"${TMP_LVM_SYSTEM_DIR}\" ] \
|
|
cache_dir = \"${TMP_LVM_SYSTEM_DIR}/cache\"
|
|
global_filter = [ \"a|.*|\" ] \
|
|
${FILTER}
|
|
} \
|
|
global { \
|
|
use_lvmetad = 0 \
|
|
}"
|
|
|
|
$LVM dumpconfig ${LVM_OPTS} --file ${LVMCONF} --mergedconfig --config "${CMD_CONFIG_LINE}"
|
|
|
|
checkvalue $? "Failed to generate ${LVMCONF}"
|
|
# Only keep TMP_LVM_SYSTEM_DIR if it contains something worth keeping
|
|
[ -n "${DEBUG}" ] && KEEP_TMP_LVM_SYSTEM_DIR=1
|
|
|
|
### set to use new lvm.conf
|
|
export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR}
|
|
|
|
# Check if there are any PVs that don't belong to any VG
|
|
# or even if there are disks which are not PVs at all.
|
|
NOVGDEVLIST=`${LVM} pvs -a -o pv_name --select vg_name="" --noheadings`
|
|
checkvalue $? "Failed to collect information for PV check"
|
|
if [ -n "${NOVGDEVLIST}" ]; then
|
|
FOLLOWLIST=""
|
|
while read PVNAME; do
|
|
FOLLOW=`$READLINK $PVNAME`
|
|
FOLLOWLIST="$FOLLOWLIST $FOLLOW"
|
|
done <<< "`echo "${NOVGDEVLIST}"`"
|
|
die 8 "Specified devices don't belong to a VG:$FOLLOWLIST"
|
|
fi
|
|
|
|
#####################################################################
|
|
### Rename the VG(s) and change the VG and PV UUIDs.
|
|
#####################################################################
|
|
VGLIST=`${LVM} vgs -o vg_name,vg_exported,vg_missing_pv_count --noheadings --binary`
|
|
checkvalue $? "Failed to collect VG information"
|
|
|
|
while read VGNAME VGEXPORTED VGMISSINGPVCOUNT; do
|
|
if [ $VGMISSINGPVCOUNT -gt 0 ]; then
|
|
echo "Volume Group ${VGNAME} has unknown PV(s), skipping."
|
|
echo "- Were all associated PV(s) supplied as arguments?"
|
|
continue
|
|
fi
|
|
|
|
if [ "$VGEXPORTED" = "1" ]; 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
|
|
|
|
"$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid --config 'global{activation=0}' --select "vg_name=${VGNAME}"
|
|
checkvalue $? "Unable to change all PV uuids in VG ${VG_NAME}"
|
|
|
|
NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"`
|
|
|
|
"$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid --config 'global{activation=0}' ${VGNAME}
|
|
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
|
|
|
|
CHANGES_MADE=1
|
|
done <<< "`echo "${VGLIST}"`"
|
|
|
|
#####################################################################
|
|
### Restore the old environment
|
|
#####################################################################
|
|
### set to use old lvm.conf
|
|
if [ -z "${ORIG_LVM_SYS_DIR}" ]
|
|
then
|
|
unset LVM_SYSTEM_DIR
|
|
else
|
|
LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR}
|
|
fi
|
|
|
|
### update the device cache and make sure all
|
|
### the device nodes we need are straight
|
|
if [ ${CHANGES_MADE} -eq 1 ]
|
|
then
|
|
# get global/use_lvmetad config and if set also notify lvmetad about changes
|
|
# since we were running LVM commands above with use_lvmetad=0
|
|
eval $(${LVM} dumpconfig ${LVM_OPTS} global/use_lvmetad)
|
|
if [ "$use_lvmetad" = "1" ]
|
|
then
|
|
echo "Notifying lvmetad about changes since it was disabled temporarily."
|
|
echo "(This resolves any WARNING message about restarting lvmetad that appears above.)"
|
|
LVM_OPTS="${LVM_OPTS} --cache"
|
|
fi
|
|
|
|
"$LVM" vgscan ${LVM_OPTS} --mknodes
|
|
fi
|
|
|
|
exit 0
|