分类:
2005-08-30 17:40:36
#! /bin/sh
#
# mirrorRoot - mirrors the root disk cleanly and safely
#
################################################################
# Author: Todd Stansell # $Id: mirrorRoot,v 1.21 2004-02-01 03:40:20-08 todd Exp $
#
# Notes:
#
# 1) I use vxprint -F ... throughout this script because of the
# fact that vxprint -ht output is not consistent between versions.
# Version 3.1 adds information about replication (since it's
# now integrated). Anyway, by pulling only the information
# I need, I can be sure it will work without regard to version.
#
# 2) status codes of all veritas commands are documented in the
# vxintro manpage.
#
# 3) versions previous to 1.18 don't deal with the Block0
# subdisk correctly for VxVM 3.5. So, make sure you're
# using version 1.18 or newer. You wouldn't see this
# message if you weren't, though.
#
################################################################ #! /bin/sh
#
# mirrorRoot - mirrors the root disk cleanly and safely
#
################################################################
# Author: Todd Stansell # $Id: mirrorRoot,v 1.21 2004-02-01 03:40:20-08 todd Exp $
#
# Notes:
#
# 1) I use vxprint -F ... throughout this script because of the
# fact that vxprint -ht output is not consistent between versions.
# Version 3.1 adds information about replication (since it's
# now integrated). Anyway, by pulling only the information
# I need, I can be sure it will work without regard to version.
#
# 2) status codes of all veritas commands are documented in the
# vxintro manpage.
#
# 3) versions previous to 1.18 don't deal with the Block0
# subdisk correctly for VxVM 3.5. So, make sure you're
# using version 1.18 or newer. You wouldn't see this
# message if you weren't, though.
#
################################################################
mirror_dev="c0t1d0"
mirror_name="rootdisk2"
verbose=0
c_opt=false
setswaponly=false
PATH=$PATH:/usr/sbin:/etc/vx/bin
PROG=`basename $0`
USAGE="usage: $PROG [-hvc] [ [-s] | [-n name] [-d device] ]
-h help
-s create swap slices and configure dump device only
-v increase verbosity level (two -v's for max)
-c show vx commands as they are run
-n name disk access name of mirror disk (default is $mirror_name)
-d device device used to mirror onto (default is $mirror_dev)"
#
# kills off any processes that are running in the background
#
cleanup() {
vxtask abort $PROG
}
#
# echo a message if we want vx command verbosity
#
show() { [ $c_opt ] && /bin/echo "# $@" ; }
#
# echo a message if we want verbosity
#
msg() { [ $verbose -ge 1 ] && /bin/echo "$@" ; }
#
# usage: showstatus $value $prog $msg
#
showstatus() {
status="$1"
prog="$2"
if [ $status -ne 0 ] ; then
echo "$3" >&2
echo " $prog exited with status $status" >&2
exit $status
fi
}
#
# Check to see that $device has at least $size sectors
# usage: check_size $device $size
#
check_size() {
len=`vxprint -e 'sd && sd_disk="'$dm_of_rootvol'" && p0 = "PRIVATE"' -F "%len" | awk '{a=a+$1}END{print '$2'-a}'`
pub_len=`vxdisk list $1 | awk -F= '/^public:/ {print $NF}'`
if [ $pub_len -lt $len ] ; then
echo "$mirror_dev is only $pub_len sectors, while" >&2
echo "$dm_of_rootvol uses $len sectors. Please choose a larger disk." >&2
exit 7
fi
}
#
# usage: initdisk $device
#
initdisk() {
dev=$1
# see if we need the old_layout option to vxdisksetup. This
# is required if we have a fully-utilized disk that has been
# encapsulated, so that only 1 cylinder is used for the private
# region, and the new disk will have enough public space to
# mirror everything to. If you don't want it to use this option,
# then initialize the disk before running this script.
opt=""
if grep old_layout /etc/vx/bin/vxdisksetup >/dev/null ; then
opt="old_layout"
fi
msg "Initializing $dev for use with volume manager"
show "vxdisksetup -i $dev $opt"
vxdisksetup -i $dev $opt; status=$?
showstatus $status vxdisksetup "Could not initialize $dev"
}
#
# adds a device ($dev) to a disk group ($dg) with specified media name ($dm)
#
# usage: add_to_dg $dev $dm [$dg]
#
add_to_dg() {
dg=rootdg
dev=$1
dm=$2
[ "$3" ] && dg=$3
msg "Adding $dev to $dg as $dm"
show "vxdg -g $dg adddisk $dm=$dev"
vxdg -g $dg adddisk $dm=$dev; status=$?
showstatus $status vxdg "Could not add $dev to $dg as "$dm""
}
#
# Display the running tasks with the current date
#
# usage: showtasks
#
showtasks() {
echo ============= `date` =============
vxtask -l list $PROG | egrep "Operation|Work|Progress|^$"
}
#
# simply waits for all tasks with our taskid ($PROG) have finished
#
# usage: taskwait
#
taskwait() {
out=`vxtask list $PROG 2>&1`
status=$?
i=0; o=`echo "$out" | wc -l`
[ $status -eq 0 -a $verbose -ge 2 ] && showtasks
while [ $status -eq 0 ] ; do
if [ $verbose -ge 2 ] ; then
u=`echo "$out" | wc -l`
if [ $u -ne $o ] ; then
showtasks
o=$u
fi
j=`expr $i % 4`
case $j in
0) /bin/echo '|
c' ;;
1) /bin/echo '/
c' ;;
2) /bin/echo '-
c' ;;
3) /bin/echo '\
c' ;;
esac
i=`expr $i + 1`
fi
sleep 2
out=`vxtask list $PROG 2>&1`
status=$?
done
}
#
# usage: mirrorto $dmname
#
mirrorto() {
dm=$1
#
# We start by mirroring rootvol, since it's special
#
msg "Starting mirror of rootvol to $dm..."
show "vxrootmir -t $PROG $dm"
vxrootmir -t $PROG $dm ; status=$?
showstatus $status vxrootmir "Could not mirror rootvol to $dm"
#
# Now mirror the rest of the volumes.
#
for vol in $vols_on_dm ; do
if [ $vol = "rootvol" ] ; then
continue
fi
msg "Starting mirror of $vol onto $dm..."
show "vxassist -b -g rootdg -t $PROG mirror $vol $dm"
vxassist -b -g rootdg -t $PROG mirror $vol $dm; status=$?
showstatus $status vxassist "Mirror of $vol onto $dm FAILED"
done
taskwait
}
#
# make sure swap has a valid partition entry so
# we can use it as a dump device, and also set
# dumpadm to use that new slice.
#
setSwap() {
swap=`vxprint -g rootdg -e 'sd && assoc.assoc.v_use_type="swap"' -F '%name'`
if [ -n "swap" ] ; then
msg "Making sure $swap has valid partition entries."
slice=""
for sd in $swap ; do
# vxmksdpart -g rootdg show "vxmksdpart -g rootdg $sd 1 0x03 0x01"
if [ -z "$slice" ] ; then
slice="`vxprint -g rootdg -F '%device_tag' $sd`s1"
fi
done
if [ -f /etc/dumpadm.conf ] ; then
if [ -n "$slice" ] ; then
msg "Configuring dumpadm for swap slice $slice"
show "dumpadm -d /dev/dsk/$slice"
else
echo "Could not determine slice to use for dump device!" >&2
fi
fi
fi
}
#############################################
# BEGIN MAIN PROGRAM
#############################################
#
# lets try to clean things up if we die
#
trap cleanup 1 2 3 5 15
while getopts vcsn:d:h c; do
case $c in
v) verbose=`expr $verbose + 1`
;;
c) c_opt="true"
;;
n) mirror_name=$OPTARG
;;
d) mirror_dev=$OPTARG
;;
s) setswaponly=true
;;
*) echo "$USAGE" >&2
exit 64
;;
esac
done
shift `expr $OPTIND - 1`
#########
# Make sure a bunch of stuff is ok before we begin
#########
# make sure we're root
if /bin/id | grep -v '^uid=0(' >/dev/null ; then
echo "$PROG: must be run as root" >&2
exit 64
fi
# make sure vxvm is installed
if pkginfo VRTSvxvm >/dev/null 2>&1 ; then
version=`pkginfo -x VRTSvxvm | tail -1 | sed 's/.*) (.).*/1/'`
else
echo "$PROG: VRTSvxvm not installed" >&2
exit 64
fi
# make sure vxvm is 3.x or greater
if [ -z "$version" -o $version -lt 3 ] ; then
echo "$PROG: This script requires VRTSvxvm 3.x or greater to function." >&2
exit 64
fi
# make sure we're encapsulated
vxprint -g rootdg rootvol >/dev/null
if [ $? -ne 0 ] ; then
echo "$PROG: rootvol doesn't exist. This probably means" >&2
echo "your root disk is not encapsulated yet." >&2
exit 64
fi
if $setswaponly ; then
setSwap
exit
fi
#########
# Now we should be ready to go...
#########
#
# Find out where we're mirroring from, and what that includes.
#
dm_of_rootvol=`vxprint -r -g rootdg -F "%rtype %name" rootvol |
awk '/^dm/{print $NF; exit}'`
dev_of_rootvol=`vxprint -g rootdg -F "%device_tag" $dm_of_rootvol`
msg "using $dm_of_rootvol to determine volumes to mirror..."
sds_on_dm=`vxprint -g rootdg
-e 'sd_disk = "'$dm_of_rootvol'"'
-F "%name" | sort`
plexs_on_dm=`vxprint -g rootdg
-e 'pl_subdisk.sd_disk = "'$dm_of_rootvol'"'
-F "%name" | sort`
vols_on_dm=`vxprint -g rootdg
-e 'v_plex.pl_subdisk.sd_disk = "'$dm_of_rootvol'"'
-F "%name" | sort`
msg " volumes to be mirrored: "$vols_on_dm
size_of_dm=`vxprint -F "%len" $sds_on_dm | awk '{a=a+$1}END{print a}'`
msg " total space required: $size_of_dm sectors"
#
# Check if $mirror_dev is being used already.
#
msg "Checking "$mirror_dev" for use as destination mirror..."
for dg in `vxdg -q list | grep -v rootdg | awk '{print $1}'` ; do
dev=`vxprint -d -g $dg -F "%name %device_tag" |
awk '$NF=="'$mirror_dev'" {print $1}'`
if [ ! -z "$dev" ] ; then
echo "$mirror_dev is used in the $dg disk group as $dev" >&2
exit 5
fi
done
#
# We check to see if $mirror_dev is part of rootdg
#
dm_mirror=`vxprint -d -g rootdg -F "%name %device_tag" |
awk '$NF=="'$mirror_dev'" {print $1}'`
if [ -n "$dm_mirror" ] ; then
#
# $mirror_dev is already part of rootdg, now see if it's being used
#
sd_num=`vxprint -F "%sd_num" $dm_mirror`
if [ $sd_num -gt 0 ] ; then
echo "$dm_mirror ($mirror_dev) already belongs to rootdg and" >&2
echo "contains $sd_num subdisks. Please choose a different" >&2
echo "device to use or clean out $mirror_dev" >&2
exit 6
fi
#
# verify space requirements
#
check_size $mirror_dev $size_of_dm
else
#
# the device ($mirror_dev) is not part of a disk group. Now we
# check if it is currently initialized. If not, we initialize it.
# Then, we make sure it's part of rootdg.
#
dm_mirror=$mirror_name
show "vxdisk list $mirror_dev"
vxdisk list $mirror_dev | grep "^private:" >/dev/null; status=$?
if [ $status -eq 0 ] ; then
#
# the disk is initialized already
#
msg "$mirror_dev is already initialized and unallocated."
else
initdisk $mirror_dev
fi
#
# verify device is large enough
#
check_size $mirror_dev $size_of_dm
#
# now add the disk to rootdg
#
add_to_dg $mirror_dev $dm_mirror rootdg
fi
#
# At this point, we have an initialized, clean disk in rootdg
# named $dm_mirror that is large enough to hold all of the volumes.
#
mirrorto $dm_mirror
#
# Now we need to check if the original disk was an encapsulated
# one, or if it was already converted to an initialized one.
#
priv=`vxprint -e 'sd &&
sd_disk="'$dm_of_rootvol'" &&
putil0!=""'
-F "%name"`
# $priv should now be something like "rootdiskPriv" or "rootdisk1Priv"
if [ -n "$priv" ] && echo $sds_on_dm | grep "$priv" >/dev/null ; then
msg "$dm_of_rootvol appears to be encapsulated, continuing..."
else
msg "$dm_of_rootvol does not appear to be encapsulated. We're done."
exit 0
fi
msg "Removing all mirrors that use $dm_of_rootvol..."
for vol in $vols_on_dm ; do
msg " removing from $vol...c"
show "vxassist -g rootdg remove mirror $vol !$dm_of_rootvol"
vxassist -g rootdg remove mirror $vol !$dm_of_rootvol; status=$?
if [ $status -ne 0 ] ; then
msg "FAILED"
fi
showstatus $status vxassist "Failed to remove mirror of $vol"
msg "ok"
done
#
# remove the encapsulation private subdisk (typically, rootdiskPriv)
#
if [ -z "$priv" ] ; then
echo "No private subdisk found? This isn't normally the case."
else
if vxprint -e 'sd && sd_name="'%priv'"' >/dev/null ; then
show "vxedit -g rootdg rm $priv"
vxedit -g rootdg rm $priv
status=$?
showstatus $status vxedit "Failed to remove $priv subdisk from rootdg"
fi
fi
#
# remove disk from rootdg
#
msg "Removing $dm_of_rootvol from rootdg..."
show "vxdg -g rootdg rmdisk $dm_of_rootvol"
vxdg -g rootdg rmdisk $dm_of_rootvol; status=$?
showstatus $status vxdg "Failed to remove $dm_of_rootvol from rootdg"
#
# re-initialize the disk
#
initdisk $dev_of_rootvol
#
# add the disk to rootdg
#
add_to_dg $dev_of_rootvol $dm_of_rootvol rootdg
#
# mirroring volumes.
#
mirrorto $dm_of_rootvol
setSwap