1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00
lvm2/scripts/vgimportclone.sh
Zdenek Kabelac f678052385 shellcheck: updates
Ehance some shellcheck reported issues.
2021-04-23 23:00:55 +02:00

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)
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