[Dovecot] Dovecot NFS Indexes and IMAP Migration

Andy Dills andy at xecu.net
Wed Feb 27 08:49:22 EET 2008


Hi there,

After being extremely impressed from implementing it in some customer 
installations, I've decided to migrate our mail infrastructure to dovecot. 
Being able to have /bin/checkpassword support across the board for pop, 
imap, and smtp authentication, as well as being able to ditch stunnel for 
the SSL layer...where were you in 2001?!? :)

I have two concerns, the first is about the proper index configuration in 
our environment, and the second is about the best way to migrate 
mailboxes.

Some quick background: we've long been distributed, with an L4 switch up 
front and a Netapp in the back, Mysql for metadata. We have a cluster of 
several FreeBSD boxes doing filtering and maildir delivery 
(postfix/amavisd-new), and we have a server that users get sent to for 
pop/imap. If it's down, they get sent to one of the filter boxes instead.

So, regarding the indexes:

>From reading the docs, it appears I would not be able to use the dovecot 
LDA due to locking issues (bummer), and I should configure dovecot to 
store index files on a local disk of the primary pop/imap server rather 
than on the netapp.

My first question would be, how much of a performance hit should I expect 
from having to update the indexes when mail is checked rather then when 
mail is delivered since I can't use the LDA? Is this a minor issue like I 
expect, or can it be something the user actually notices when checking 
mail?

In a worst case scenario, if the pop/imap server is down, and another 
server is used, how long would it take to create an index for an account 
with a few hundered megs, several thousand messages? I'm wondering if, 
since I have plenty of overhead available on the netapp, I should just 
store the indexes there in case another server must be used. 

I'm basically looking for more information about the pros and cons of 
storing the indexes on the nfs volume in a situation where a single server 
would normally be providing pop/imap service.

Regarding migration:

My concerns regarding migration relate to how best to process existing 
maildirs by both converting the previous imap metadata and calculating an 
initial index for each account.

First off, I can't seem to find any info on a way to create an initial 
index file for all of the mailboxes. Can anybody suggest a command I can 
use for this? I'm sure I just overlooked it.

Regarding the migrations, we have both courier and bincimap to deal with. 
(We use qmail's pop, so no complications with migrating courier).

Fortunately, courier is used for normal imap on 143, bincimap is only used 
for webmail. So, it would seem that metadata from bincimap could be 
ignored; the only thing it would seem important to preserve is mailbox 
subscriptions. Please correct this assumption if I'm wrong.

bincimap uses a INBOX/folder format in the subscription file, however the 
actual folders are stored exactly the same as the INBOX.folder style of 
courier.

So, it seems like my best option is to modify the 
courier-dovecot-migrate.pl script to consider the mailboxes subscribed to 
via bincimap. Here's a modified convert_subscriptions that seems to work 
well in limited testing, feel free to point out any idiot mistakes, it's 
been a while since I've done anything substantial in perl. I would have 
sent a patch but I suspect I'm the only person who will ever use this 
change and critiquing it would be easier with a full context. 

sub convert_subscriptions {
  my ($dir, $owner_uid, $owner_gid) = @_;
      
  my $in_fname = "$dir/courierimapsubscribed";

  # ADDED: The bincimap file to parse

  my $in_fname2 = "$dir/.bincimap-subscribed";
  my $out_fname = "$dir/subscriptions";

  # MODIFIED: Return only if neither exist

  return if (!-f $in_fname && !-f $in_fname2);
      
  if (!$overwrite && -f $out_fname) {
    print "$out_fname already exists, not overwritten\n" if (!$quiet);
    return;
  }
      
  return if (!$do_conversion);

  my ($fin, $fin2, $fout);
  open ($fin, $in_fname) || die $!;
  open ($fin2, $in_fname2) || die $!;
  open ($fout, ">$out_fname") || die $!;

  # ADDED: An array to track mailboxes we've written in case both files exist

  my @subs;
  while (<$fin>) {
    chomp $_;
       
    if (/^INBOX$/i) {
      print $fout "INBOX\n";
      push @subs, "INBOX\n";
    } elsif (/^INBOX\.(.*)$/i) {
      print $fout "$1\n";
      push @subs, "$1\n";
    } else {
      # unknown. keep it as-is.
      print $fout "$_\n";
      push @subs, "$_\n";  
    }
  }
  close $fin;

  # ADDED: A second loop, same as the first, but also checking to make 
  # sure that the mailbox has not already been written to the new file to 
  # eliminate duplicates. 

  while (<$fin2>) {
    chomp $_;
    my $sub = $_;
    if (/^INBOX$/i && !grep (/^INBOX\n/i, @subs)) {
      print $fout "INBOX\n";
    } elsif (/^INBOX\/(.*)$/i && !grep (/^$1\n/i, @subs)) {
      print $fout "$1\n";
    } elsif (!grep(/^$sub\n/, @subs)) {
      # unknown. keep it as-is.
      print $fout "$sub\n";   
    }
  }
  close $fin;
  close $fin2;
  close $fout;
  chown $owner_uid, $owner_gid, $out_fname;
}


Thanks in advance for any help or suggestions!
Andy

---
Andy Dills
Xecunet, Inc.
www.xecu.net
301-682-9972
---


More information about the dovecot mailing list