]> sourceware.org Git - lvm2.git/blob - scripts/vgimportclone.sh
thin: tighten discard string conversions
[lvm2.git] / scripts / vgimportclone.sh
1 #!/bin/bash
2
3 # Copyright (C) 2009 Chris Procter All rights reserved.
4 # Copyright (C) 2009 Red Hat, Inc. All rights reserved.
5 #
6 # This file is part of LVM2.
7 #
8 # This copyrighted material is made available to anyone wishing to use,
9 # modify, copy, or redistribute it subject to the terms and conditions
10 # of the GNU General Public License v.2.
11 #
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software Foundation,
14 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 #
16 # vgimportclone: This script is used to rename the VG and change the associated
17 # VG and PV UUIDs (primary application being HW snapshot restore)
18
19 # following external commands are used throughout the script
20 # echo and test are internal in bash at least
21 RM=rm
22 BASENAME=basename
23 MKTEMP=mktemp
24 AWK=awk
25 CUT=cut
26 TR=tr
27 READLINK=readlink
28 GREP=grep
29 GETOPT=getopt
30
31 # user may override lvm location by setting LVM_BINARY
32 LVM="${LVM_BINARY:-lvm}"
33
34 die() {
35 code=$1; shift
36 echo "Fatal: $@" 1>&2
37 exit $code
38 }
39
40 "$LVM" version >& /dev/null || die 2 "Could not run lvm binary '$LVM'"
41
42
43 function getvgname {
44 ### get a unique vg name
45 ### $1 = list of exists VGs
46 ### $2 = the name we want
47 VGLIST=$1
48 VG=$2
49 NEWVG=$3
50
51 BNAME="${NEWVG:-${VG}}"
52 NAME="${BNAME}"
53 I=0
54
55 while [[ "${VGLIST}" =~ "${NAME}" ]]
56 do
57 I=$(($I+1))
58 NAME="${BNAME}$I"
59 done
60 echo "${NAME}"
61 }
62
63
64 function checkvalue {
65 ### check return value and error if non zero
66 if [ $1 -ne 0 ]
67 then
68 die $1 "$2, error: $1"
69 fi
70 }
71
72
73 function usage {
74 ### display usage message
75 echo "Usage: ${SCRIPTNAME} [options] PhysicalVolume [PhysicalVolume...]"
76 echo " -n|--basevgname - Base name for the new volume group(s)"
77 echo " -i|--import - Import any exported volume groups found"
78 echo " -t|--test - Run in test mode"
79 echo " --quiet - Suppress output"
80 echo " -v|--verbose - Set verbose level"
81 echo " -d|--debug - Set debug level"
82 echo " --version - Display version information"
83 echo " -h|--help - Display this help message"
84 echo ""
85 exit 1
86 }
87
88
89 function cleanup {
90 #set to use old lvm.conf
91 LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR}
92
93 if [ $KEEP_TMP_LVM_SYSTEM_DIR -eq 1 ]; then
94 echo "${SCRIPTNAME}: LVM_SYSTEM_DIR (${TMP_LVM_SYSTEM_DIR}) must be cleaned up manually."
95 else
96 "$RM" -rf -- "${TMP_LVM_SYSTEM_DIR}"
97 fi
98 }
99
100 SCRIPTNAME=`"$BASENAME" $0`
101
102
103 if [ "$UID" != "0" -a "$EUID" != "0" ]
104 then
105 die 3 "${SCRIPTNAME} must be run as root."
106 fi
107
108 LVM_OPTS=""
109 TEST_OPT=""
110 DISKS=""
111 # for compatibility: using mktemp -t rather than --tmpdir
112 TMP_LVM_SYSTEM_DIR=`"$MKTEMP" -d -t snap.XXXXXXXX`
113 KEEP_TMP_LVM_SYSTEM_DIR=0
114 CHANGES_MADE=0
115 IMPORT=0
116 DEBUG=""
117 VERBOSE=""
118 VERBOSE_COUNT=0
119 DEVNO=0
120
121 if [ -n "${LVM_SYSTEM_DIR}" ]; then
122 export ORIG_LVM_SYS_DIR="${LVM_SYSTEM_DIR}"
123 fi
124
125 trap cleanup 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
126
127 #####################################################################
128 ### Get and check arguments
129 #####################################################################
130 OPTIONS=`"$GETOPT" -o n:dhitv \
131 -l basevgname:,debug,help,import,quiet,test,verbose,version \
132 -n "${SCRIPTNAME}" -- "$@"`
133 [ $? -ne 0 ] && usage
134 eval set -- "$OPTIONS"
135
136 while true
137 do
138 case $1 in
139 -n|--basevgname)
140 NEWVG="$2"; shift; shift
141 ;;
142 -i|--import)
143 IMPORT=1; shift
144 ;;
145 -t|--test)
146 TEST_OPT="-t"
147 shift
148 ;;
149 --quiet)
150 LVM_OPTS="--quiet ${LVM_OPTS}"
151 shift
152 ;;
153 -v|--verbose)
154 let VERBOSE_COUNT=VERBOSE_COUNT+1
155 if [ -z "$VERBOSE" ]
156 then
157 VERBOSE="-v"
158 else
159 VERBOSE="${VERBOSE}v"
160 fi
161 shift
162 ;;
163 -d|--debug)
164 if [ -z "$DEBUG" ]
165 then
166 DEBUG="-d"
167 set -x
168 else
169 DEBUG="${DEBUG}d"
170 fi
171 shift
172 ;;
173 --version)
174 "$LVM" version
175 shift
176 exit 0
177 ;;
178 -h|--help)
179 usage; shift
180 ;;
181 --)
182 shift; break
183 ;;
184 *)
185 usage
186 ;;
187 esac
188 done
189
190 # turn on DEBUG (special case associated with -v use)
191 if [ -z "$DEBUG" -a $VERBOSE_COUNT -gt 3 ]; then
192 DEBUG="-d"
193 set -x
194 fi
195
196 # setup LVM_OPTS
197 if [ -n "${DEBUG}" -o -n "${VERBOSE}" ]
198 then
199 LVM_OPTS="${LVM_OPTS} ${DEBUG} ${VERBOSE}"
200 fi
201
202 # process remaining arguments (which should be disks)
203 for ARG
204 do
205 if [ -b "$ARG" ]
206 then
207 PVS_OUT=`"${LVM}" pvs ${LVM_OPTS} --noheadings -o vg_name "$ARG" 2>/dev/null`
208 checkvalue $? "$ARG is not a PV."
209 PV_VGNAME=$(echo $PVS_OUT | $GREP -v '[[:space:]]+$')
210 [ -z "$PV_VGNAME" ] && die 3 "$ARG is not in a VG."
211
212 ln -s "$ARG" ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}
213 DISKS="${DISKS} ${TMP_LVM_SYSTEM_DIR}/vgimport${DEVNO}"
214 DEVNO=$((${DEVNO}+1))
215 else
216 die 3 "$ARG is not a block device."
217 fi
218 done
219
220 ### check we have suitable values for important variables
221 if [ -z "${DISKS}" ]
222 then
223 usage
224 fi
225
226 #####################################################################
227 ### Get the existing state so we can use it later
228 #####################################################################
229
230 OLDVGS=`"${LVM}" vgs ${LVM_OPTS} -o name --noheadings 2>/dev/null`
231 checkvalue $? "Current VG names could not be collected without errors"
232
233 #####################################################################
234 ### Prepare the temporary lvm environment
235 #####################################################################
236
237 for BLOCK in ${DISKS}
238 do
239 FILTER="\"a|^${BLOCK}$|\", ${FILTER}"
240 done
241 export FILTER="filter=[ ${FILTER} \"r|.*|\" ]"
242
243 LVMCONF=${TMP_LVM_SYSTEM_DIR}/lvm.conf
244
245 # FIXME convert to cmdline override
246 "$LVM" dumpconfig ${LVM_OPTS} | \
247 "$AWK" -v DEV=${TMP_LVM_SYSTEM_DIR} -v CACHE=${TMP_LVM_SYSTEM_DIR}/.cache \
248 -v CACHE_DIR=${TMP_LVM_SYSTEM_DIR}/cache \
249 '/^[ \t]*filter[ \t]*=/{print ENVIRON["FILTER"];next} \
250 /^[ \t]*scan[ \t]*=/{print "scan = [ \"" DEV "\" ]";next} \
251 /^[ \t]*cache[ \t]*=/{print "cache = \"" CACHE "\"";next} \
252 /^[ \t]*use_lvmetad[ \t]*=/{print "use_lvmetad = 0";next} \
253 /^[ \t]*cache_dir[ \t]*=/{print "cache_dir = \"" CACHE_DIR "\"";next} \
254 {print $0}' > ${LVMCONF}
255
256 checkvalue $? "Failed to generate ${LVMCONF}"
257 # Only keep TMP_LVM_SYSTEM_DIR if it contains something worth keeping
258 [ -n "${DEBUG}" ] && KEEP_TMP_LVM_SYSTEM_DIR=1
259
260 # verify the config contains the filter, scan and cache_dir (or cache) config keywords
261 "$GREP" -q '^[[:space:]]*filter[[:space:]]*=' ${LVMCONF} || \
262 die 5 "Temporary lvm.conf must contain 'filter' config."
263 "$GREP" -q '^[[:space:]]*scan[[:space:]]*=' ${LVMCONF} || \
264 die 6 "Temporary lvm.conf must contain 'scan' config."
265
266 # check for either 'cache' or 'cache_dir' config values
267 "$GREP" -q '[[:space:]]*cache[[:space:]]*=' ${LVMCONF}
268 CACHE_RET=$?
269 "$GREP" -q '^[[:space:]]*cache_dir' ${LVMCONF}
270 CACHE_DIR_RET=$?
271 [ $CACHE_RET -eq 0 -o $CACHE_DIR_RET -eq 0 ] || \
272 die 7 "Temporary lvm.conf must contain 'cache' or 'cache_dir' config."
273
274 ### set to use new lvm.conf
275 export LVM_SYSTEM_DIR=${TMP_LVM_SYSTEM_DIR}
276
277
278 #####################################################################
279 ### Rename the VG(s) and change the VG and PV UUIDs.
280 #####################################################################
281
282 PVINFO=`"${LVM}" pvs ${LVM_OPTS} -o pv_name,vg_name,vg_attr --noheadings --separator : 2>/dev/null`
283 checkvalue $? "PV info could not be collected without errors"
284
285 # output VG info so each line looks like: name:exported?:disk1,disk2,...
286 VGINFO=`echo "${PVINFO}" | \
287 "$AWK" -F : '{{sub(/^[ \t]*/,"")} \
288 {sub(/unknown device/,"unknown_device")} \
289 {vg[$2]=$1","vg[$2]} if($3 ~ /^..x/){x[$2]="x"}} \
290 END{for(k in vg){printf("%s:%s:%s\n", k, x[k], vg[k])}}'`
291 checkvalue $? "PV info could not be parsed without errors"
292
293 for VG in ${VGINFO}
294 do
295 VGNAME=`echo "${VG}" | "$CUT" -d: -f1`
296 EXPORTED=`echo "${VG}" | "$CUT" -d: -f2`
297 PVLIST=`echo "${VG}" | "$CUT" -d: -f3- | "$TR" , ' '`
298
299 if [ -z "${VGNAME}" ]
300 then
301 FOLLOWLIST=""
302 for DEV in $PVLIST; do
303 FOLLOW=`"$READLINK" $DEV`
304 FOLLOWLIST="$FOLLOW $FOLLOWLIST"
305 done
306 die 8 "Specified PV(s) ($FOLLOWLIST) don't belong to a VG."
307 fi
308
309 if [ -n "${EXPORTED}" ]
310 then
311 if [ ${IMPORT} -eq 1 ]
312 then
313 "$LVM" vgimport ${LVM_OPTS} ${TEST_OPT} "${VGNAME}"
314 checkvalue $? "Volume Group ${VGNAME} could not be imported"
315 else
316 echo "Volume Group ${VGNAME} exported, skipping."
317 continue
318 fi
319 fi
320
321 ### change the pv uuids
322 if [[ "${PVLIST}" =~ "unknown" ]]
323 then
324 echo "Volume Group ${VGNAME} has unknown PV(s), skipping."
325 echo "- Were all associated PV(s) supplied as arguments?"
326 continue
327 fi
328
329 for BLOCKDEV in ${PVLIST}
330 do
331 "$LVM" pvchange ${LVM_OPTS} ${TEST_OPT} --uuid ${BLOCKDEV} --config 'global{activation=0}'
332 checkvalue $? "Unable to change PV uuid for ${BLOCKDEV}"
333 done
334
335 NEWVGNAME=`getvgname "${OLDVGS}" "${VGNAME}" "${NEWVG}"`
336
337 "$LVM" vgchange ${LVM_OPTS} ${TEST_OPT} --uuid "${VGNAME}" --config 'global{activation=0}'
338 checkvalue $? "Unable to change VG uuid for ${VGNAME}"
339
340 ## if the name isn't going to get changed dont even try.
341 if [ "${VGNAME}" != "${NEWVGNAME}" ]
342 then
343 "$LVM" vgrename ${LVM_OPTS} ${TEST_OPT} "${VGNAME}" "${NEWVGNAME}"
344 checkvalue $? "Unable to rename ${VGNAME} to ${NEWVGNAME}"
345 fi
346
347 CHANGES_MADE=1
348 done
349
350 #####################################################################
351 ### Restore the old environment
352 #####################################################################
353 ### set to use old lvm.conf
354 if [ -z "${ORIG_LVM_SYS_DIR}" ]
355 then
356 unset LVM_SYSTEM_DIR
357 else
358 LVM_SYSTEM_DIR=${ORIG_LVM_SYS_DIR}
359 fi
360
361 ### update the device cache and make sure all
362 ### the device nodes we need are straight
363 if [ ${CHANGES_MADE} -eq 1 ]
364 then
365 "$LVM" vgscan ${LVM_OPTS} --mknodes
366 fi
367
368 exit 0
This page took 0.054425 seconds and 5 git commands to generate.