> On Thu, Nov 15, 2001 at 09:58:09AM -0600, John Wade wrote:
>
> > If anyone is interested in the full set of steps, I could post it to the
> > list.
Hi All,
Since a number of people requested it, I am sending my complete list of steps (with
added comments) for moving from one Cyrus server to another. Sorry about the size of
this posting
I used this procedure to migrate two servers from older Pentium Pro hardware running
Cyrus 1.5.19 to newer P3 Xeon servers running Cyrus 2.0.16. One server had ~20,000
accounts and 10GB of mail, the other had ~1300 accounts and 35GB of mail. These
instructions assume that you have both servers set up and fully tested before moving
the users' data. Our new environment uses:
RedHat 7.0 (2.2.19 kernel)
Cyrus 2.0.16 for IMAP
Cyrus SASL 1.5.24 with LDAP authentication (via hacked pwcheck)
qmail 1.0.3 as the MTA
ezmlm-idx for mailing lists
WebSieve and Easysieve for sieve
The mail on the old server was all stored in a single 35GB ext2fs file system mounted
as /var. Within this file system, we had hashed the mail spool via cyrus partitions
using the first letter of the user's login id to choose the partition (i.e.
/var/spool/imap/a/ for abelincoln ) This is similar to the new hashmailspool option.
On the new server, we had a 190GB array and I was afraid to make this a single file
system. In order to end up with a managable number of file systems (of manageable
size) , we decided to store mail in 5 - 33GB file systems ( mounted
as/var/spool/imap/0, /var/spool/imap/1, /var/spool/imap/2, /var/spool/imap/3 and
/var/spool/imap/4) This corresponded to 5 matching Cyrus partitions (0,1,2,3,4)
IMPORTANT DISCLAIMER: While I sometimes feel like I know what I am doing, there is no
guarranty that I did this in the most efficient way or even that I did it correctly,
all I know is that it seems to have worked for me
Warning, Since I was using external authentication (via LDAP), there is nothing here
about moving the authentication database.
The following instructions were designed so that I could cut and paste it to reduce
mistakes
and speed the conversion. All comments are proceeded by a # Sometimes the
instructions
call for editing files with vi, in this case, the next set of lines separated by
#--------
are what should be the new contents of the edited file.
----------------------------------------------------------------------------------
#Cleanup newserver
# On new server shutdown services
# The cyrus and pwcheck scripts are ones I put together to control cyrus and pwcheck.
# basically this step was just to kill all existing services on the new box
# your steps will differ.
/etc/rc.d/init.d/cyrus stop
/etc/rc.d/init.d/pwcheck stop
/etc/rc.d/init.d/qmailctl stop
/etc/rc.d/init.d/httpd stop
# Cleanup any existing mail directories, quotas, seen and subscription files, etc that
might be
#left over from testing
rm -f /var/imap/proc/*
rm -f /var/imap/mailboxes*
rm -f /var/imap/db/*.*
rm -f /var/imap/deliverdb/*.db
rm -f /var/imap/deliverdb/db/*
# delete subscriptions and seen files
cd /var/imap/user
for dir in `ls -d ?`; do rm -f /var/imap/user/$dir/* ; done
# delete quotas
cd /var/imap/quota
for dir in `ls -d ?`; do rm -f /var/imap/quota/$dir/* ; done
# delete sieve scripts (note this is not the default sieve directory)
cd /var/imap/sieve
for dir in `ls -d ?`; do rm -Rf /var/imap/sieve/$dir/* ; done
#Delete the mail spool (note we use multiple partitions in /var/spool/imap)
cd /var/spool/imap
for dir in `ls -d ?`; do rm -Rf /var/spool/imap/$dir/* ; done
# cleanp ezmlm mailing lists
# (This step omited from this posting since this is ezmlm specific)
# done with cleanup
# At this point the new server should be completely cleaned up and
# ready for the copy
-------------------------------------------------------------
# Restore Overview
# We need to restore all items in
# /var/imap/user/
# /var/imap/quota/
# /var/imap/mailboxes (file)
# /var/spool/imap/
#NFS Setup. I mounted the new server's file systems on the old server
# because we had a problem with the nfs install on the old server, ideally,
# I would have mounted the old on the new because then I could have done
# it read only and not risked any mistakes.
#on newserver, setup an export for each mount point that will need to have files
copied to it.
vi /etc/exports
#-------------------------------
/var oldserver.oakton.edu(rw,no_root_squash)
/var/imap oldserver.oakton.edu(rw,no_root_squash)
/var/spool/imap/0 oldserver.oakton.edu(rw,no_root_squash)
/var/spool/imap/1 oldserver.oakton.edu(rw,no_root_squash)
/var/spool/imap/2 oldserver.oakton.edu(rw,no_root_squash)
/var/spool/imap/3 oldserver.oakton.edu(rw,no_root_squash)
/var/spool/imap/4 oldserver.oakton.edu(rw,no_root_squash)
#-------------------------------
/etc/rc.d/init.d/nfs stop
/etc/rc.d/init.d/nfslock stop
/etc/rc.d/init.d/portmap stop
/etc/rc.d/init.d/portmap start
/etc/rc.d/init.d/nfslock start
/etc/rc.d/init.d/nfs start
# to reload (if you make future changes to /etc/exports )
#exportfs -a
#on old server mount nfs shares from new server
mkdir -p /mnt/newserver/var
mount -t nfs newserver.oakton.edu:/var /mnt/newserver/var
mount -t nfs newserver.oakton.edu:/var/imap /mnt/newserver/var/imap
mount -t nfs newserver.oakton.edu:/var/spool/imap/0 /mnt/newserver/var/spool/imap/0
mount -t nfs newserver.oakton.edu:/var/spool/imap/1 /mnt/newserver/var/spool/imap/1
mount -t nfs newserver.oakton.edu:/var/spool/imap/2 /mnt/newserver/var/spool/imap/2
mount -t nfs newserver.oakton.edu:/var/spool/imap/3 /mnt/newserver/var/spool/imap/3
mount -t nfs newserver.oakton.edu:/var/spool/imap/4 /mnt/newserver/var/spool/imap/4
# On Old Server
#increase quotas to allow mail to be delivered (We often have users over quota,
# and their mail is hanging out in the queue waiting for either the user to clean up
# their mailbox or for 10 days to elapse so it can bounce
# by increasing the quota, I allowed all this mail to be delivered and did not have
# to move the MTA's queue (We were going to increase the quota on the new
# server anyway). Note this script could have been writen to use the IMAP::Admin
# module instead of Net::Telnet, but we already had the basic framework and
# IMAP::Admin was not a part of cyrus 1.5
# get a listof all existing quotas
ls /var/imap/quota > /root/currentusers.txt
#create script
vi /root/adjquota.pl
---------------------------
#!/usr/bin/perl -w
use Net::Telnet;
use File::Find;
$hostname = "oldserver.oakton.edu";
$username = "<cyrus admin>";
$passwd = "password";
$quota = 60000;
## Open up a new session to imap server
$imap = new Net::Telnet (Telnetmode => 0);
$imap->open(Host => $hostname, Port => 143);
## Read connection message.
$line = $imap->getline;
die $line unless $line =~ /^\* OK/;
print "connected to imap server ok\n";
## Send admin user name.
$imap->print(". login $username $passwd");
$line = $imap->getline;
die $line unless $line =~ /^\. OK/;
print "logged in to imap server ok\n";
## Read each entry in file
open (P, "currentusers.txt") or die "Can't find the currentusers.txt file\n";
while (<P>) {
chomp;
$imap->print(qq{. setquota $_ (storage $quota)});
$line = $imap->getline;
die "$_ " . $line unless $line =~ /^\. OK/;
print "quota root set to $quota for $_\n";
}
close(P);
$imap->print(". logout");
exit;
-------------------------------
chmod 700 /root/adjquota.pl
/root/adjquota.pl
# Signal qmail to re-attempt delivery (Your MTA will work differently)
ps -ef | grep qmail-send
#Get process id
kill -SIGALRM <PID>
#check queue
qmHandle -s
qmHandle -L | less
#Adjust quotas if necessary to allow delivery
cyradm -u <cyrus admin> localhost
lqm user.<username>
sql user.<username> 65000
quit
#repeat SIGALRM and queue check until no mail is queued locally
#shutdown services on old server
Stop all mail services (shutdown qmail)
Comment out imapd line in /etc/inetd.conf - this disables people's ability to use IMAP
to access their
email. Then kill -HUP <inetd pid>
#Copy mailboxes file (on old server)
cp /var/imap/mailboxes /mnt/newserver/var/imap/mailboxes
#on old server
# (in Cyrus 1.5 quotas were all in one directory, in 2.0.16, the are hashed by the
first letter
# of the username, this script will put all of them in the correct directory (unless
they begin with a
# number or other character :-)
vi /root/CopyImapQuotas.sh
-------------------------------
# To copy quotas
for letter in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
echo $letter
cp /var/imap/quota/user.$letter* /mnt/newserver/var/imap/quota/$letter/
done
---------------------------------
chmod 700 CopyImapQuotas.sh
/root/CopyImapQuotas.sh
# Same thing for subscriptions
vi /root/CopyImapSub.sh
-------------------------------
# To copy subscriptions
for letter in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
echo $letter
cp /var/imap/user/$letter*.sub /mnt/newserver/var/imap/user/$letter/
done
---------------------------------
chmod 700 CopyImapSub.sh
/root/CopyImapSub.sh
# Create CopyImapSpool.sh script on old server and execute
# Note that this script is more complicated than others might need
# because we were trying to redistribute users into a new partitioning
# structure. On the old server a user's mail would have been in a partition
# based on the first letter of their name. For example, my directory would
#have been /var/spool/imap/j/user/jwade
#On the new server, we wanted to evenly distribute users into 5 partitions
#so that we could keep the file system size managable and evenly distribute
#disk space usage between the mount points.
# The idhash program that I use in the following script is a little program I wrote
#C (I also have a perl version) that calculates the partition number by adding
# up the ascii values of all the characters in the user's name, dividing by five
# and using the remainder. (modulus operator) This fairly simple hash function
# gives a pretty good distribution of users.
#Our script to add users uses this same "idhash" program to assing new users
#to partitions in the same way.
vi /root/CopyImapSpool.sh
------------------------------------------------------
# To copy users
# make sure directories exist
for num in 0 1 2 3 4
do
mkdir /mnt/newserver/var/spool/imap/$num/user/
done
# copy mail
for letter in a b c d e f g h i j k l m n o p q r s t u v w x y z
do
echo $letter
cd /var/spool/imap/$letter/user
for uid in *
do
echo $letter $uid `/root/idhash -n $uid`
cp -R /var/spool/imap/$letter/user/$uid
/mnt/newserver/var/spool/imap/`/root/idhash -n $uid`/user/
done
done
-----------------------------------
chmod 700 CopyImapSpool.sh
/root/CopyImapSpool.sh
# for 35GB of mail (1,668,019 files), this process took 6 hours 32 minutes. This was
far faster than when
# we tested it doing a backup and restore from tape
#on old server copy ezmlm files
(Step omitted here for brevity
#----------------------------------------------------------------------
#Steps to complete After Restore
# on newserver
#Next sections are to fix up file ownership, hopefully the umask took
# care of permissions
#fix subscrptions
chown -R cyrus:mail /var/imap/user/*
#fix quotas
chown -R cyrus:mail /var/imap/quota/*
#fix mail spool
chown -R cyrus:mail /var/spool/imap/*
#fix ezmlm
# (step omitted here for brevity)
# fix Mailboxes file
# I needed to do three things with the mailboxes file, change everyone's partitions
#to match our new partitioning structure (switch from a-z to 0-4), change the cyrus
admin user's permissions
#from "d" to"c" so that we could delete mailboxes (This was a change between
# 1.5.x and 2.0.x) and convert the flat text mailboxes file into the Berkeley DB that
2.0.x
# needs
cp /var/imap/mailboxes /var/imap/mailboxes.old
# the following perl script is what fixes the partition (using that same idhash
program)
# and fixes the permissions for the cyrus admin user, I can cheat here, since I
# know the cyrus admin user's acl is the last entry on each line in our mailboxes
file.
vi /root/fixmailboxes.pl
------------------------------------
while (<>) {
$line = $_;
# find login id
/^user\.(\w+)/;
# calculate new partition
$idhash = `idhash -n $1`;
# fix partition replace a-z with calculated 0-4
$line =~ s/(^user\.\w+[^\t]*\t)([a-z])/$1$idhash/ ;
# fix permissions for cyrus admin user
$line =~ s/d\t$/c\t/;
print $line;
}
-----------------------------------
perl -w /root/fixmailboxes.pl < /var/imap/mailboxes.old > /var/imap/mailboxes
# The following steps are used to convert the old malbox text file (after cleanup)
# to the new berkeley db
# for those who need more info about ctl_mboxlist, see the man page
#basically, the two options that apply to conversions are -u to convert
#from text file to db and -d to dump from db to text file
chown cyrus:mail /var/imap/mailboxes
su cyrus
cd /var/imap
/usr/cyrus/bin/ctl_mboxlist -u < mailboxes
/usr/cyrus/bin/ctl_mboxlist -c
exit
# Disconnect on old server
cat /etc/mtab
umount -t nfs newserver.oakton.edu:/var/imap
umount -t nfs newserver.oakton.edu:/var/spool/imap/0
umount -t nfs 1newserver.oakton.edu:/var/spool/imap/1
umount -t nfs newserver.oakton.edu:/var/spool/imap/2
umount -t nfs newserver.oakton.edu:/var/spool/imap/3
umount -t nfs newserver.oakton.edu:/var/spool/imap/4
umount -t nfs newserver.oakton.edu:/var
#shutdown rpc and nfs on new server (for security)
/etc/rc.d/init.d/nfs stop
/etc/rc.d/init.d/nfslock stop
/etc/rc.d/init.d/portmap stop
chkconfig --level 123456 nfs off
chkconfig --level 123456 nfslock off
chkconfig --level 123456 portmap off
chkconfig --list | less
#verify copy (do on both boxes)
#Verify count of subscriptions
#on old server
ls /var/imap/user/* | wc -l
#on new server
ls /var/imap/user/?/* | wc -l
#Verify count of quotas
#on old server
ls /var/imap/quota/* | wc -l
#on new server
ls /var/imap/quota/?/* | wc -l
#Verify count of spool dirs
#on old server
ls -ld /var/spool/imap/?/user/* | wc -l
#on new server
ls -ld /var/spool/imap/?/user/* | wc -l
#check count of files
#on old server
ls -R /var/spool/imap/?/user/* | wc -l
#on new server
ls -R /var/spool/imap/?/user/* | wc -l
# restart services
/etc/rc.d/init.d/pwcheck start
/etc/rc.d/init.d/cyrus start
qmailctl start
/etc/rc.d/init.d/httpd start
# test everything !!!!!
#if it is really bad, you can just go back to the old server at this point
# Change IP Address and hostname. Verify files with :
#convert name and ip
#Since we wanted to use the same dns name and ip address for the new server,
#at this point, we powered off the old server
#to make sure I found all references to the host name and ip address, I had previosly
searched the
#file system fir them
#on new server before copy
for dir in bin boot command dev etc home lib mnt nsr opt package root sbin service tmp
usr var
do
echo checking $dir
find /$dir -type f -exec grep -l "192\.168\.5\.105" {} \;
done
for dir in bin boot command dev etc home lib mnt nsr opt package root sbin service
tmp
usr var
do
echo checking $dir
find /$dir -type f -exec grep -l "newserver" {} \;
done
#this found the following files
# edit each and replace new ip (192.168.5.105) with old ip (192.168.5.5)
/etc/sysconfig/network-scripts/ifcfg-eth0
/etc/hosts
#these two are from qmail
/etc/smtp.txt
/etc/smtp.cdb
# edit following files and replace "newserver" with "oldserver" in
/etc/sysconfig/network
/etc/hosts
#qmail specific
/var/qmail/control/me
/var/qmail/control/locals
/var/qmail/control/rcpthosts
# paths omitted below for web stuff
websieve.conf
easysieve.pl
horde/imp/config/defaults.php3
#reboot
shutdown -r now
#At this point queued mail on our mail relay started to be delivered, and everything
was fine.
#I have omtted a couple of steps here that were specific to imp (moving prefs and
addressbook) and ezmlm
# ( moving mailing lists)
I still wonder if I should have reconstructed all the mailboxes (with
/usr/cyrus/bin/reconstruct) and fixed the quotas (/usr/cyrus/bin/quota -f ) before
proceeding, but I did not
Hope this was helpful,
John