Multipath installation script

This script is intended to be used on IBM Blade Server HS20/HS21 to install the multipath tools on Debian.

#!/bin/bash
#
# file: multipath.sh
# author: Sylvain Bolay
# e-mail: sylvain.bolay@irovision.ch
# date: May 29, 2007
#
# GOALS: 
#
 
 
distro="Debian"
distroFile="/etc/issue"
kernel="2.6.18"
backupExt=`date +%y%m%d%H%M%S`
 
date
echo -e "Script to configure multipath on SAN"
echo -e "with the Debian stable etch distribution\n"
echo -n "Checking distribution... "
 
#check distro
if [ ! -f $distroFile ]; then
	echo "ABORTED!"
	echo "The $distroFile file is not present!"
	echo "This script is for a Debian distribution!"
	exit
fi
 
if [ `grep -c -i "Debian" /etc/issue` -eq 0 ]; then
	echo "ABORTED!"
	echo "This script is for a Debian distribution!"
	exit
fi
 
#check kernel
if [ `uname -r | grep -c $kernel` -eq 0 ]; then
	echo "ABORTED!"
	echo "Your kernel version is: "
	uname -r
	echo "This does not match kernel >= $kernel."
	exit
fi
 
#end of "Checking distribution..."
echo "done"
echo -n "Checking tools&drivers... "
 
#udev provides udevinfo needed thereafter
for package in grep mawk udev multipath-tools multipath-tools-initramfs dmsetup firmware-qlogic; do
	if [ `dpkg -s $package | grep -c installed` -eq 0 ]; then
		echo "ABORTED!"
		echo "$package missing! Please apt-get $package!"
		if [ $package == "firmware-qlogic" ]; then
			echo "$package is located in the non-free section!"
			echo "You may have to update your sources.list file to apt-get it!"
		fi
		exit
	fi
done
 
#end of "Checking tools&drivers..."
echo "done"
echo -n "Backup and Create configuration files... "
 
#Check if multipath.rules exist
file="/etc/udev/rules.d/multipath.rules"
if [ ! -f $file ]; then
	echo "ABORTED!"
	echo "$file doesn't exist!"
	exit
fi
 
initramfstoolsETC="/etc/initramfs-tools"
initramfstoolsUSR="/usr/share/initramfs-tools"
if [ ! -d $initramfstoolsUSR ]; then
	echo "ABORTED!"
	echo "$initramfstoolsUSR directory is missing!"
	exit
fi
 
# backup (I do not check if the backup directory already exists or not)
# I should find in "/etc/initramfs-tools/scripts/local-top" the file multipath_script
if [ -d $initramfstoolsETC ]; then
	mv $initramfstoolsETC $initramfstoolsETC.$backupExt
fi
 
cp -r $initramfstoolsUSR $initramfstoolsETC
 
#end of "Backup and Create configuration files... "
echo "done"
echo -n "Check module availability... "
 
#add module to "modules" file
modulesFile="$initramfstoolsETC/modules"
if [ -f $modulesFile ]; then
	# dm-mpath and dm-multipath are from /usr/share/doc/multipath-tools/FAQ impulse!
	# for now, I suppressed dm-mpath!!!!
	# scsi_mod sd_mod dm-mod dm-multipath dm-round-robin and
	# dm-emc are from http://www.tuxyturvy.com/files/mkinitrd.mp entries
 
	for module in scsi_mod sd_mod dm-mod dm-multipath dm-round-robin dm-emc; do
		if [ `modinfo $module 2>&1 | grep -c "modinfo: could not find module"` -gt 0 ]; then
			echo "ABORTED!"
			echo "$module module does not exist."
			exit
		fi
		echo $module >> $modulesFile
	done
fi
 
#end of "Check module availability... "
echo "done"
echo -n "Modifing configurations files... "
 
#Create the initramfs.conf
initramfsconf="$initramfstoolsETC/initramfs.conf"
#PARANOIA
if [ -f $initramfsconf ]; then
	mv $initramfsconf /tmp/$initramfsconf.$backupExt
	echo "I put your $initramfsconf into /tmp with the extension: $backupExt"
fi
cat << MSG >> $initramfsconf
MODULES=most
BUSYBOX=y
BOOT=local
DEVICE=eth0
NFSROOT=auto
MSG
 
#Create the update-initramfs.conf
updateinitramfsconf="$initramfstoolsETC/update-initramfs.conf"
#PARANOIA
if [ -f $updateinitramfsconf ]; then
	mv $updateinitramfsconf /tmp/$updateinitramfsconf.$backupExt
	echo "I put your $updateinitramfsconf into /tmp with the extension: $backupExt"
fi
cat << MSG >> $updateinitramfsconf
update_initramfs=yes
backup_initramfs=yes
MSG
 
#Create the multipath.conf (very small conf!!!)
multipathConf="/etc/multipath.conf"
#backup
if [ -f $multipathConf ]; then
	mv $multipathConf $multipathConf.$backupExt	
fi
 
#I dont know yet how to automatically determine the working disk!
#I can try to identify the disk with rdev
alias="os"
disk="sda"
wwid=`/sbin/scsi_id -g -u -p 0x83 -s /block/$disk`
wwid_udev=`udevinfo --query=all --name=/dev/sda1 | grep "ID_SERIAL=" | awk '{ print $2 }' | cut -d '=' -f2`
vendor=`udevinfo --query=all --name=/dev/sda1 | grep "ID_VENDOR=" | awk '{ print $2 }' | cut -d '=' -f2`
#model=`udevinfo --query=all --name=/dev/sda1 | grep "ID_MODEL=" | awk '{ print $2 }' | cut -d '=' -f2`
model=`/sbin/scsi_id -g -p 0x80 -s /block/$disk | awk '{ print $2 }'`
 
#adjust the vendor string length to 8 ;
#this is fixed by the multipath source code to work properly
#vendorSize=8
#new setting to allow .* at the end!
vendorSize=6
size=${#vendor}
if [ $size -gt $vendorSize ]; then
	vendor=`expr substr $vendor 1 $vendorSize`
	vendor=${vendor}.*
elif [ $size -lt $vendorSize ]; then
	vendor=${vendor}.*
	#THIS DO NOT WORK
	#for (( i=$size+1; i <= $vendorSize; i++ )) do
	#vendor=${vendor}" "
	#done
fi
#echo "The vendor ($vendor) string length is about: ${#vendor}"
 
#adjust the model string length to 16 ;
#this is fixed by the multipath source code to work properly
modelSize=16
#new setting to allow .* at the end!
modelSize=14
size=${#model}
if [ $size -gt $modelSize ]; then
	model=`expr substr $model 1 $modelSize`
	model=${model}.*
elif [ $size -lt $modelSize ]; then
	model=${model}.*
	#THIS DO NOT WORK
	#for (( i=$size+1; i <= $modelSize; i++ )) do
	#model=$model" "
	#done
fi
#echo "The model ($model) string length is about: ${#model}"
 
if [ $wwid != $wwid_udev ]; then
	echo "ABORTED!"
	echo "The wwid provided by scsi_id and by udevinfo does not match!"
	echo "scsi_id: $wwid / udevinfo: $wwid_udev"
	exit
fi
 
#add defaults
#Warning space between keywords and { is imperative
#You can check if if works correctly by trying: multipath -d -v2
cat << MSG >> $multipathConf
defaults {
	udev_dir		/dev
	polling_interval	2
	#selector		"round-robin 0"
	#path_grouping_policy	group_by_serial
	getuid_callout		"/sbin/scsi_id -g -u -p 0x83 -s /block/%n"
	#prio_callout		"/sbin/mpath_prio_tpc /dev/%n"
	#path_checker            tur
	#rr_min_io		1000
	#rr_weight		uniform
	#failback                immediate
	#no_path_retry		300
	user_friendly_names	yes
}
 
MSG
 
#add blacklist
cat << MSG >> $multipathConf
blacklist {
	devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*"
	devnode "^hd[a-z][[0-9]*]"
	devnode "^cciss!c[0-9]d[0-9]*[p[0-9]*]"
}
 
MSG
 
#add multipaths
cat << MSG >> $multipathConf
multipaths {
	multipath {
		wwid $wwid
		alias $alias
	}
}
 
MSG
 
#add devices
cat << MSG >> $multipathConf
devices {
	device {
		#vendor must be exactly 8 char length
		vendor			"$vendor"
		#product must be exactly 16 char length
		product			"$model"
		path_grouping_policy    group_by_serial
		getuid_callout		"/sbin/scsi_id -g -u -p 0x83 -s /block/%n"
		prio_callout		"/sbin/mpath_prio_tpc /dev/%n"
		path_checker            tur
		path_selector           "round-robin 0"
		failback                immediate
		prio_callout		"/sbin/mpath_prio_tpc /dev/%n"
		features		"1 queue_if_no_path"
		no_path_retry		300
	}
}
 
MSG
 
 
#Create an add-on for /etc/initramfs-tools/hooks/multipath_hook as multipath_hook.1
multipathHook="$initramfstoolsETC/hooks/multipath_hook_1"
#PARANOIA
if [ -f $multipathHook ]; then
	mv $multipathHook /tmp/multipath_hook.$backupExt
	echo "I put your $multipathHook into /tmp with the extension: $backupExt"
fi
cat << MSG >> $multipathHook
#!/bin/sh
PREREQ=""
prereqs()
{
	echo "\$PREREQ"
}
 
case \$1 in
# get pre-requisites
prereqs)
        prereqs
        exit 0
        ;;
esac
 
. /usr/share/initramfs-tools/hook-functions
 
copy_exec $multipathConf /etc/
for helper in /sbin/mpath_prio_*; do
	copy_exec \$helper /sbin
done
MSG
 
#chmod $multipathHook to be executable
chmod +x $multipathHook
 
#end of "Modifing configurations files... "
echo "done"
echo -n "Checking multipath configuration file... "
 
foundAlias=0
if [ `multipath -d -v2 | grep -c $alias` -gt 0 ]; then
	foundAlias=1
fi
if [ `multipath -ll | grep -c $alias` -gt 0 ]; then
	foundAlias=1
fi
if [ ! foundAlias ]; then
	echo "ABORTED!"
	echo "It seems that the $multipathConf as a problem."
	echo "I was not able to detect the alias "$alias" while"
	echo "trying multipath -d -v2"
fi
 
#end of "Checking multipath configuration file... "
echo "done"
 
echo "I only looked at /block/$disk for now!"
echo "If you need to add some more devices, you should update your $multipathConf"
echo -e "and re-run:  update-initramfs -t -c -v -k `uname -r` "
 
echo "Create initrd... "
#Create initrd based on "/usr/share/doc/multipath-tools-initramfs/README.Debian" 
kernel=`uname -r`
initrd="/boot/initrd.img-`uname -r`"
bckinitrd="$initrd-$backupExt-original"
 
if [ -f $initrd ]; then
	mv $initrd $bckinitrd
	echo "I backuped your $initrd as $bckinitrd"
else
	echo "ABORTED!"
	echo "I tried to find your initrd in $initrd but couldn't find it!"
	echo "Did I make a mistake???"
	echo "Anyway, I will create a new initrd file as $initrd"
	echo "You may have to update your grub/menu.lst"
fi
 
update-initramfs -t -c -v -k `uname -r`
#rename the newly created initrd
mpinitrd="$initrd-$backupExt-multipath"
mv $initrd $mpinitrd
#restore the backuped initrd
cp $bckinitrd $initrd
 
#end of "Create initrd..."
echo "done"
 
echo -n "Auto-Configuration of GRUB..."
#TODO: auto-configure /boot/grub/menu.lst and /etc/fstab
#Update the /boot/grub/menu.lst
menulst="/boot/grub/menu.lst"
#PARANOIA
if [ -f $menulst ]; then
	cp $menulst $menulst.$backupExt
fi
cat << MSG >> $menulst
 
title           Debian GNU/Linux, kernel $kernel with multipath (V: $backupExt)
root            (hd0,0)
kernel          /boot/vmlinuz-$kernel root=/dev/mapper/${alias}1 ro
initrd          $mpinitrd
savedefault
 
MSG
 
#end of "Auto-Configuration of GRUB..."
echo "done"
 
echo "Dont forget to add entries in your /etc/fstab. This should be something like:"
echo "<file system>		<mount point>	<type>		<options>       <dump>  <pass>"
echo "/dev/mapper/${alias}1	/		reiserfs	notail		0	1"
echo "/dev/mapper/${alias}2	none		swap		sw		0	0"
echo ""
echo "WARNING:"
echo "You can check after rebooting if the settings are taken from the 'default' entry "
echo "of your multipath.conf file or are correctly handled by the 'device' entry"
echo "by issuing the multipath -v3 command and checking if beside your settings"
echo "the comments are '(config file default)' or '(controller setting)' respectively"
 
exit