Skip to content

Instantly share code, notes, and snippets.

@storbeck
Created September 13, 2016 23:47
Show Gist options
  • Save storbeck/849a9cbe18662914f56a47eb808378a8 to your computer and use it in GitHub Desktop.
Save storbeck/849a9cbe18662914f56a47eb808378a8 to your computer and use it in GitHub Desktop.
#!/bin/bash
#
# AUTHOR: zoite
# DATE: 02.29.2012
# PURPOSE: An automated migration script to do a 1:1 server migration
# completey independent of drive size and configuration
# Note: Supports software (mdadm) RAID
#
exec 3> /dev/tty
# Adds SSH private key to server
function add_key() {
echo "StrictHostKeyChecking no" >> ~/.ssh/config
cat > ~/.ssh/id_rsa <<KEYEND
#################################
# ADD SSH PRIVATE KEY HERE #
#################################
KEYEND
chmod 0600 ~/.ssh/id_rsa
}
# Function to display a sane progress bar for rsync
rsync_progress() {
cat >> rsync.awk << EOF
{
if (index($0, "to-check=") > 0)
{
split($0, pieces, "to-check=")
split(pieces[2], term, ")");
split(term[1], division, "/");
print (1-(division[1]/division[2]))*100"%"
}
else
{
print "#"$0;
}
fflush();
}
EOF
}
# Various dialog boxes for configuration
function discover_info() {
rm -f *.in *.ans
# Set network info for server you're migrating from
VALUES=$(dialog --backtitle "EasyMigrate" --title "Networking" --form "Networking setup" 15 50 0 \
"(old) IP:" 1 1 "" 1 10 30 0 \
"(new) Subnet: " 2 1 "" 2 15 25 0 \
2>&1 1>&3)
echo "$VALUES" > net.ans
# Set number of drives that will be used
VALUES=$(dialog --backtitle "EasyMigrate" --title "Drives" --radiolist "Number of drives" 15 50 0 \
"1" "Drive" on \
"2" "Drives" off \
"3" "Drives" off \
"4" "Drives" off \
2>&1 1>&3)
NODRIVES=$(echo $VALUES)
# Set number of partitions per drive
i=0
while [[ $NODRIVES -ne $i ]]; do
let i=$i+1
VALUES=$(dialog --backtitle "EasyMigrate" --title "Partitions" --radiolist "Number of partitions on [drive $i]" 15 50 0 \
"1" "Partition" off \
"2" "Partitions" off \
"3" "Partitions" on \
"4" "Partitions" off \
2>&1 1>&3)
NOPARTITIONS=$(echo $VALUES)
echo "drive$i $NOPARTITIONS" > drive$i.ans
done
# set partitions details
for LOOP in drive*.ans; do
DRIVE=$(echo $LOOP | cut -f1 -d.)
if [[ $DRIVE == "drive1" ]]; then DRIVE="sda"; fi
if [[ $DRIVE == "drive2" ]]; then DRIVE="sdb"; fi
if [[ $DRIVE == "drive3" ]]; then DRIVE="sdc"; fi
if [[ $DRIVE == "drive4" ]]; then DRIVE="sdd"; fi
NOPARTITIONS=$(cat $LOOP | awk '{print $2}')
i=0
while [[ $i -ne $NOPARTITIONS ]]; do
let i=$i+1
VALUES=$(dialog --backtitle "EasyMigrate" --title "Partitions" --form "Partition setup: $DRIVE$i" 15 50 0 \
"Partiton" 1 1 "$DRIVE$i" 1 10 30 0 \
"Size: " 2 1 "" 2 10 30 0 \
"Type: " 3 1 "" 3 10 30 0 \
"Mount: " 4 1 "" 4 10 30 0 \
"Label: " 5 1 "" 5 10 30 0 \
"Bootable: " 6 1 "" 6 10 30 0 \
2>&1 1>&3)
echo $VALUES >> $DRIVE-partitions.ans
done
done
# does it need raid?
VALUES=$(dialog --backtitle "EasyMigrate" --title "Raid" --radiolist "Does raid need to be setup?" 15 50 0 \
"1" "No" on \
"2" "Yes" off \
2>&1 1>&3)
echo "$VALUES" > needraid.ans
# Set it up if selected yes
NEEDRAID=$(cat needraid.ans)
if [[ $NEEDRAID == "2" ]]; then
# how many arrays?
VALUES=$(dialog --backtitle "EasyMigrate" --title "Raid" --radiolist "How many arrays need to be created?" 15 50 0 \
"1" "Array" on \
"2" "Arrays" off \
"3" "Arrays" off \
"4" "Arrays" off \
2>&1 1>&3)
NOARRAYS=$(echo $VALUES)
# set details for each array
i=0
while [[ $i -ne $NOARRAYS ]]; do
let i=$i+1
VALUES=$(dialog --backtitle "EasyMigrate" --title "Raid" --form "Details for array $i" 15 50 0 \
"Partition 1: " 1 1 "" 1 10 30 0 \
"Partition 2: " 2 1 "" 2 10 30 0 \
"Level: " 3 1 "" 3 10 30 0 \
"Device: " 4 1 "" 4 10 30 0 \
"Mount: " 5 1 "" 5 10 30 0 \
2>&1 1>&3)
echo $VALUES >> raid.ans
done
fi
}
# Auto-partition the drives based on value entered
function run_partitions() {
for DRIVES in *-partitions.ans; do
DRIVE=$(echo $DRIVES | cut -f1 -d-)
i=0;
cat $DRIVES | while read PARTITIONS SIZE TYPE MOUNT LABEL BOOT; do
let i=i+1
echo "n" >> $DRIVE-fdisk.in # new partitions
echo "p" >> $DRIVE-fdisk.in # primary
echo "$i" >> $DRIVE-fdisk.in # partition $i
echo "" >> $DRIVE-fdisk.in # default
if [[ $SIZE =~ "all" ]]; then
echo "" >> $DRIVE-fdisk.in # use rest of disk
else
echo "+$SIZE" >> $DRIVE-fdisk.in # size
fi
echo "t" >> $DRIVE-fdisk.in # type
if [[ ! $i == 1 ]]; then
echo "$i" >> $DRIVE-fdisk.in # type on partition $i
fi
echo "$TYPE" >> $DRIVE-fdisk.in # set partition type
if [[ $BOOT =~ "y" ]]; then
echo "a" >> $DRIVE-fdisk.in # set flag
echo "1" >> $DRIVE-fdisk.in # bootable
fi
done
echo "w" >> $DRIVE-fdisk.in
done
echo ""
for P1 in *-fdisk.in; do
DRIVE=$(echo "$P1" | cut -f1 -d-);
fdisk /dev/$DRIVE < $P1
sleep 5
fdisk /dev/$DRIVE << EOF
p
w
EOF
sleep 5
done
}
# Mounts the necessary system points and creates the filesystem
function build_fs_and_mount() {
mkdir /mnt/chroot
mkdir /mnt/chroot/{proc,dev,sys}
mount -t proc none /mnt/chroot/proc
mount -o bind /dev /mnt/chroot/dev
mount -o bind /sys /mnt/chroot/sys
NEEDRAID=$(cat needraid.ans)
if [[ $NEEDRAID == '1' ]]; then
for DRIVES in *-partitions.ans; do
DRIVE=$(echo $DRIVES | cut -f1 -d-)
cat $DRIVES | while read PARTITION SIZE TYPE MOUNT LABEL BOOT; do
if [[ $TYPE == "83" ]]; then
mkfs.ext3 /dev/$PARTITION
if [[ ! $LABEL =~ "none" ]]; then
tune2fs -L /dev/$PARTITION $LABEL
fi
mkdir -p /mnt/chroot/$MOUNT
mount /dev/$PARTITION /mnt/chroot/$MOUNT
elif [[ $TYPE == "82" ]]; then
mkswap /dev/$PARTITION
swapon /dev/$PARTITION
else
mkfs.ext3 /dev/$PARTITION
tune2fs -L /dev/$PARTITION $LABEL
fi
done
done
elif [[ $NEEDRAID == '2' ]]; then
cat raid.ans | while read PARTITION1 PARTITION2 LEVEL DEVICE MOUNT; do
mdadm --create --force --verbose /dev/$DEVICE --level=$LEVEL --metadata=0.90 --raid-devices=2 /dev/$PARTITION1 /dev/$PARTITION2 << EOF
y
EOF
mkfs.ext3 /dev/$DEVICE
mkdir -p /mnt/chroot/$MOUNT
mount /dev/$DEVICE /mnt/chroot/$MOUNT
done
fi
}
# Start the rsync
function copy_data() {
SERVER=$(awk '{print $1}' net.ans|head -1)
rsync --compress --archive --verbose --sparse --numeric-ids -P -t --devices --exclude=/dev --exclude=/lost+found --exclude=/mnt --exclude=/media --exclude=/proc --exclude=/srv --exclude=/sys --progress root@$SERVER:/ /mnt/chroot/ | awk -f rsync.awk |
dialog --backtitle "EasyMigrate" --gauge "Copying files" 10 70 0
}
# Update the configuration files
function update_confs() {
SERVER=$(head -1 net.ans)
NETMASK=$(tail -1 net.ans)
# NOTE: This is configured for a DELL SC1435
# Update modprobe on sc1435
echo "alias eth0 tg3
alias eth1 tg3
alias scsi_hostadapter sata_svw
alias usb-controller ehci-hcd
alias usb-controller1 ohci-hcd
install appletalk /bin/true
install ipx /bin/true
install irda /bin/true
install x25 /bin/true
install pppox /bin/true
install bluetooth /bin/true
install sctp /bin/true
install ax25 /bin/true
alias CPU0 powernow-k8
install ib_addr /bin/true
install ib_cm /bin/true
install ib_core /bin/true
install ib_mad /bin/true
install ib_sa /bin/true
install ib_sdp /bin/true
install ib_ucm /bin/true
install ib_umad /bin/true
install ib_uverbs /bin/true
install iw_cm /bin/true
install ppp_generic /bin/true
install rdma_cm /bin/true
install slhc /bin/true" > /mnt/chroot/etc/modprobe.conf
# create ifcfg-eth0
LASTOCT=$(echo $SERVER|cut -f4 -d.)
FIRSTPART=$(echo $SERVER|rev|cut -f2- -d.|rev)
let LASTOCT=$LASTOCT-1
GATEWAY="$FIRSTPART.$LASTOCT"
echo "DEVICE=eth0
BOOTPROTO=static
IPADDR=$SERVER
NETMASK=$NETMASK
GATEWAY=$GATEWAY
ONBOOT=yes
TYPE=Ethernet
" > /mnt/chroot/etc/sysconfig/network-scripts/ifcfg-eth0
# disable ifcfg-eth1
echo "DEVICE=eth1
ONBOOT=no" > /mnt/chroot/etc/sysconfig/network-scripts/ifcfg-eth1
}
# Update network settings - includes auto-update for Plesk and cPanel
function update_network() {
#IP_MAP=`dialog --stdout --title "Please choose a file" --fselect $HOME/ip_map 14 48`
IP_MAP=ip_map
if [ -d /mnt/chroot/var/named/run-root/ ]; then
NAMEDIR="/var/named/run-root/var/*"
else
NAMEDIR="/var/named/chroot/var/named/"
fi
cat $IP_MAP | while read old new
do
if [[ ! $new == "" ]]; then
(grep -Zls $old /mnt/chroot/etc/* /mnt/chroot/var/cpanel/* /mnt/chroot/var/cpanel/users/* /mnt/chroot/${NAMEDIR} /mnt/chroot/var/named/*;
grep -rZls $old /mnt/chroot/etc/httpd/conf/* /mnt/chroot/etc/sysconfig/* /mnt/chroot/usr/local/apache/conf/* /mnt/chroot/var/cpanel/userdata/ /mnt/chroot/etc/webmin/*) | xargs -0 sed -i s/$old/$new/g || echo "no matches found" 1>/dev/null 2>/dev/null
fi
done
echo "nameserver 208.67.220.220" > /mnt/chroot/etc/resolv.conf
# Plesk reconfigurator
if [ -d /mnt/chroot/usr/local/psa ]; then
NETMASK=$(tail -1 net.ans)
cat ip_map | while read old new; do
if [[ ! $new == "" ]];
then echo "eth0:$old $NETMASK -> eth0:$new $NETMASK" >> /mnt/chroot/tmp/PLESKIPMAP
fi;
done
if [ ! -d /mnt/chroot/usr/local/psa/tmp ]; then
mkdir /mnt/chroot/usr/local/psa/admin/logs; mkdir /mnt/chroot/usr/local/psa/tmp
fi
chmod 777 /mnt/chroot/usr/local/psa/admin/logs
chmod 777 /mnt/chroot/usr/local/psa/tmp
chroot /mnt/chroot /etc/init.d/mysqld start
chroot /mnt/chroot /usr/local/psa/bin/reconfigurator.pl /tmp/PLESKIPMAP
chroot /mnt/chroot /etc/init.d/mysqld stop
chroot /mnt/chroot /usr/local/psa/bin/reconfigurator.pl /tmp/PLESKIPMAP
else
echo "Plesk not running"
fi
}
# This shouldn't be used. It's for a use-case specific to me
function build_kernel() {
# install kernel with sata_svw support
chroot /mnt/chroot wget http://mirror.centos.org/centos/4/os/i386/CentOS/RPMS/kernel-2.6.9-89.EL.i586.rpm
chroot /mnt/chroot wget http://mirror.centos.org/centos/4/os/i386/CentOS/RPMS/kernel-devel-2.6.9-89.EL.i586.rpm
chroot /mnt/chroot rpm -ivh --oldpackage kernel*.rpm
# build initrd
cd /mnt/chroot/boot
INITNUM=$(cat /mnt/chroot/boot/grub/menu.lst |grep -v \# |grep default|awk '{print substr($0,length,1)}')
INITNUM=$((${INITNUM}+1)) # So it doesn't start at 0
IMGFILE=$(cat /mnt/chroot/boot/grub/menu.lst | grep -v \# | grep initrd | sed -n "${INITNUM}p" | awk -F/ '{print $NF}')
KERN=$( echo ${IMGFILE} | sed 's/initrd-//g' | sed 's/\.img//g' )
rm -f /mnt/chroot/boot/${IMGFILE}
chroot /mnt/chroot mkinitrd -f -v --preload libata --preload mptsas --preload ata_piix --preload sata_svw --builtin=ata_generic /boot/${IMGFILE} ${KERN}
# install grub
chroot /mnt/chroot grub-install --recheck /dev/sda
CHKGRUB=$(file -s /dev/sda | grep boot )
if [ -z "${CHKGRUB}" ]; then
echo "Grub install failed"; exit
fi
}
add_key
discover_info
run_partitions
build_fs_and_mount
rsync_progress
copy_data
update_confs
update_network
build_kernel
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment