mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
337 lines
9.4 KiB
Bash
Executable File
337 lines
9.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Copyright (C) 2009 Chris Procter All rights reserved.
|
|
# Copyright (C) 2009-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 ] && [ "$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 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" ] && [ "$VERBOSE_COUNT" -gt 3 ]; then
|
|
DEBUG="-d"
|
|
set -x
|
|
fi
|
|
|
|
# setup LVM_OPTS
|
|
if [ -n "$DEBUG" ] || [ -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 -r 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 -r 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 ${VGNAME}"
|
|
|
|
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
|